/**
 * E2E Tests for Backward Compatibility - Orchestrated Auth Mode
 *
 * Tests that the split-auth-package refactoring maintains backward compatibility:
 * - Stateful sessions work correctly
 * - Token signing and verification
 * - Consent-based tool access
 * - Session vault operations
 * - Token refresh handling
 *
 * These tests ensure existing orchestrated auth integrations continue to work
 * after the auth package extraction.
 */
import { expect, test } from '@frontmcp/testing';

test.describe('Orchestrated Auth Backward Compatibility E2E', () => {
  test.use({
    server: 'apps/e2e/demo-e2e-orchestrated/src/main.ts',
    project: 'demo-e2e-orchestrated',
    // Pin the server's JWT secret so the test token factory signs HS256 with the
    // SAME secret — the server now cryptographically verifies gateway tokens, so
    // fixture tokens must be genuinely valid (not merely well-formed).
    env: { JWT_SECRET: 'orchestrated-e2e-shared-secret-0123456789' },
  });

  test.describe('Stateful Session Compatibility', () => {
    test('should create and maintain stateful session', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-stateful-compat',
        scopes: ['read', 'write'],
      });

      const client = await server.createClient({ token });

      // Session should be created
      expect(client.sessionId).toBeDefined();
      expect(client.sessionId.length).toBeGreaterThan(0);

      // Session should persist across calls
      const tools = await client.tools.list();
      expect(tools).toBeDefined();

      const resources = await client.resources.list();
      expect(resources).toBeDefined();

      await client.disconnect();
    });

    test('should maintain session state across tool calls', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-state-compat',
        scopes: ['read', 'write'],
      });

      const client = await server.createClient({ token });

      // Create a note - should succeed
      const createResult = await client.tools.call('create-note', {
        title: 'State Test Note',
        content: 'Testing session state',
      });
      expect(createResult).toBeSuccessful();
      expect(createResult).toHaveTextContent('State Test Note');

      // Make another call in the same session to verify session state is maintained
      const listResult = await client.tools.call('list-notes', {});
      expect(listResult).toBeSuccessful();
      // Note: list-notes returns mock data, but the fact that both calls succeed
      // verifies session is maintained across multiple tool calls

      await client.disconnect();
    });

    test('should have consistent session ID across requests', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-session-id-compat',
        scopes: ['read'],
      });

      const client = await server.createClient({ token });
      const initialSessionId = client.sessionId;

      // Multiple requests should maintain same session
      await client.tools.list();
      await client.resources.list();
      await client.prompts.list();

      // Session ID should not change
      expect(client.sessionId).toBe(initialSessionId);

      await client.disconnect();
    });
  });

  test.describe('Token Signing Compatibility', () => {
    test('should accept locally signed tokens', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-sign-compat',
        scopes: ['read', 'write'],
        email: 'sign-test@example.com',
        name: 'Sign Test User',
      });

      const client = await server.createClient({ token });

      expect(client.isConnected()).toBe(true);
      expect(client.auth.isAnonymous).toBe(false);

      await client.disconnect();
    });

    test('should extract claims from signed token', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-claims-compat',
        scopes: ['admin', 'read', 'write'],
        email: 'claims@example.com',
        name: 'Claims User',
      });

      const client = await server.createClient({ token });

      // User claims should be available
      expect(client.auth.user).toBeDefined();
      expect(client.auth.user?.sub).toBe('user-claims-compat');

      await client.disconnect();
    });
  });

  test.describe('JWKS Endpoint Compatibility', () => {
    test('should serve JWKS endpoint for token verification', async ({ server }) => {
      const response = await fetch(`${server.info.baseUrl}/.well-known/jwks.json`, {
        method: 'GET',
        headers: { Accept: 'application/json' },
      });

      // JWKS must be available for orchestrated mode
      expect(response.status).toBe(200);
      const jwks = await response.json();
      expect(jwks.keys).toBeDefined();
      expect(Array.isArray(jwks.keys)).toBe(true);
      // Must have at least one signing key
      expect(jwks.keys.length).toBeGreaterThanOrEqual(1);
    });
  });

  test.describe('Authorization Metadata Compatibility', () => {
    test('should serve OAuth authorization server metadata', async ({ server }) => {
      const response = await fetch(`${server.info.baseUrl}/.well-known/oauth-authorization-server`, {
        method: 'GET',
        headers: { Accept: 'application/json' },
        redirect: 'manual',
      });

      // Should be 200 or redirect (redirects are acceptable for federation)
      expect([200, 301, 302, 307, 308]).toContain(response.status);

      if (response.status === 200) {
        const metadata = await response.json();
        // Standard OAuth AS metadata fields
        expect(metadata).toBeDefined();
      }
    });
  });

  test.describe('Full MCP Capability Compatibility', () => {
    test('should support all tool operations with auth', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-tool-compat',
        scopes: ['read', 'write'],
      });

      const client = await server.createClient({ token });

      // List tools
      const tools = await client.tools.list();
      expect(tools.length).toBeGreaterThan(0);

      // Call tools
      const noteResult = await client.tools.call('create-note', {
        title: 'Compat Note',
        content: 'Testing compatibility',
      });
      expect(noteResult).toBeSuccessful();

      const taskResult = await client.tools.call('create-task', {
        title: 'Compat Task',
        priority: 'medium',
      });
      expect(taskResult).toBeSuccessful();

      await client.disconnect();
    });

    test('should support all resource operations with auth', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-resource-compat',
        scopes: ['read'],
      });

      const client = await server.createClient({ token });

      // List resources
      const resources = await client.resources.list();
      expect(resources.length).toBeGreaterThan(0);

      // Read resources
      const notesContent = await client.resources.read('notes://all');
      expect(notesContent).toBeDefined();

      await client.disconnect();
    });

    test('should support all prompt operations with auth', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-prompt-compat',
        scopes: ['read'],
      });

      const client = await server.createClient({ token });

      // List prompts
      const prompts = await client.prompts.list();
      expect(prompts.length).toBeGreaterThan(0);

      // Get prompt
      const result = await client.prompts.get('summarize-notes', {});
      expect(result.messages).toBeDefined();
      expect(result.messages.length).toBeGreaterThan(0);

      await client.disconnect();
    });
  });

  test.describe('Error Response Compatibility', () => {
    test('should return 401 for unauthenticated requests', async ({ server }) => {
      const response = await fetch(`${server.info.baseUrl}/`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json, text/event-stream',
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          id: 1,
          method: 'initialize',
          params: { capabilities: {}, clientInfo: { name: 'test', version: '1.0' } },
        }),
      });

      expect(response.status).toBe(401);
      expect(response.headers.get('WWW-Authenticate')).toContain('Bearer');
    });

    test('should return proper error for invalid token', async ({ server }) => {
      const response = await fetch(`${server.info.baseUrl}/`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json, text/event-stream',
          Authorization: 'Bearer invalid.token.value',
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          id: 1,
          method: 'initialize',
          params: { capabilities: {}, clientInfo: { name: 'test', version: '1.0' } },
        }),
      });

      expect(response.status).toBe(401);
    });
  });

  test.describe('Multi-User Compatibility', () => {
    test('should isolate sessions between different users', async ({ server, auth }) => {
      const token1 = await auth.createToken({
        sub: 'user-multi-1',
        scopes: ['read', 'write'],
      });

      const token2 = await auth.createToken({
        sub: 'user-multi-2',
        scopes: ['read', 'write'],
      });

      const client1 = await server.createClient({ token: token1 });
      const client2 = await server.createClient({ token: token2 });

      // Should have different session IDs
      expect(client1.sessionId).not.toBe(client2.sessionId);

      // Should have different user identities
      expect(client1.auth.user?.sub).toBe('user-multi-1');
      expect(client2.auth.user?.sub).toBe('user-multi-2');

      // Actions should be isolated
      await client1.tools.call('create-note', {
        title: 'User 1 Note',
        content: 'From user 1',
      });

      await client2.tools.call('create-note', {
        title: 'User 2 Note',
        content: 'From user 2',
      });

      await client1.disconnect();
      await client2.disconnect();
    });

    test('should handle concurrent users', async ({ server, auth }) => {
      const tokens = await Promise.all([
        auth.createToken({ sub: 'concurrent-1', scopes: ['read', 'write'] }),
        auth.createToken({ sub: 'concurrent-2', scopes: ['read', 'write'] }),
        auth.createToken({ sub: 'concurrent-3', scopes: ['read', 'write'] }),
      ]);

      const clients = await Promise.all(tokens.map((token) => server.createClient({ token })));

      // All clients should be connected
      expect(clients.every((c) => c.isConnected())).toBe(true);

      // All should have unique sessions
      const sessionIds = clients.map((c) => c.sessionId);
      const uniqueSessionIds = new Set(sessionIds);
      expect(uniqueSessionIds.size).toBe(clients.length);

      // Cleanup
      await Promise.all(clients.map((c) => c.disconnect()));
    });
  });

  test.describe('Session Data Compatibility', () => {
    test('should persist data within session', async ({ server, auth }) => {
      const token = await auth.createToken({
        sub: 'user-data-persist',
        scopes: ['read', 'write'],
      });

      const client = await server.createClient({ token });

      // Create multiple items
      await client.tools.call('create-note', { title: 'Note 1', content: 'First' });
      await client.tools.call('create-note', { title: 'Note 2', content: 'Second' });
      await client.tools.call('create-task', { title: 'Task 1', priority: 'high' });

      // All should be retrievable
      const notes = await client.tools.call('list-notes', {});
      expect(notes).toBeSuccessful();

      const tasks = await client.tools.call('list-tasks', {});
      expect(tasks).toBeSuccessful();

      await client.disconnect();
    });
  });
});
