/**
 * @license
 * Copyright 2026 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { describe, it, expect, vi } from 'vitest';
import {
  MCPOAuthClientProvider,
  type OAuthAuthorizationResponse,
} from './mcp-oauth-provider.js';
import type {
  OAuthClientInformation,
  OAuthClientMetadata,
  OAuthTokens,
} from '@modelcontextprotocol/sdk/shared/auth.js';

describe('MCPOAuthClientProvider', () => {
  const mockRedirectUrl = 'http://localhost:8090/callback';
  const mockClientMetadata: OAuthClientMetadata = {
    client_name: 'Test Client',
    redirect_uris: [mockRedirectUrl],
    grant_types: ['authorization_code', 'refresh_token'],
    response_types: ['code'],
    token_endpoint_auth_method: 'client_secret_post',
    scope: 'test-scope',
  };
  const mockState = 'test-state-123';

  describe('oauth flow', () => {
    it('should support full OAuth flow', async () => {
      const onRedirectMock = vi.fn();
      const provider = new MCPOAuthClientProvider(
        mockRedirectUrl,
        mockClientMetadata,
        mockState,
        onRedirectMock,
      );

      // Step 1: Save client information
      const clientInfo: OAuthClientInformation = {
        client_id: 'my-client-id',
        client_secret: 'my-client-secret',
      };
      provider.saveClientInformation(clientInfo);

      // Step 2: Save code verifier
      provider.saveCodeVerifier('my-code-verifier');

      // Step 3: Set up callback server
      const mockAuthResponse: OAuthAuthorizationResponse = {
        code: 'authorization-code',
        state: mockState,
      };
      const mockServer = {
        port: Promise.resolve(8090),
        waitForResponse: vi.fn().mockResolvedValue(mockAuthResponse),
        close: vi.fn().mockResolvedValue(undefined),
      };
      provider.saveCallbackServer(mockServer);

      // Step 4: Redirect to authorization
      const authUrl = new URL('http://auth.example.com/authorize');
      await provider.redirectToAuthorization(authUrl);

      // Step 5: Save tokens after exchange
      const tokens: OAuthTokens = {
        access_token: 'final-access-token',
        token_type: 'Bearer',
        expires_in: 3600,
        refresh_token: 'final-refresh-token',
      };
      provider.saveTokens(tokens);

      // Verify all data is stored correctly
      expect(provider.clientInformation()).toEqual(clientInfo);
      expect(provider.codeVerifier()).toBe('my-code-verifier');
      expect(provider.state()).toBe(mockState);
      expect(provider.tokens()).toEqual(tokens);
      expect(onRedirectMock).toHaveBeenCalledWith(authUrl);
      expect(provider.getSavedCallbackServer()).toBe(mockServer);
    });
  });
});
