import { test, expect } from '@playwright/test';
import { APIInterceptor } from '../utils/api-interceptor';
import { WebSocketMonitor } from '../utils/websocket-monitor';
import { compareAPISequences } from '../utils/sequence-comparator';
import {
  loginToJamUI,
  navigateToSessionCreation,
  fillSessionForm,
  verifySessionInterfaceLoaded,
  waitForAPICalls,
  extractSessionId,
} from '../utils/test-helpers';
import * as fs from 'fs';
import * as path from 'path';

test.describe('Complete Session Flow E2E', () => {
  test('complete flow: login → create session → join session', async ({ page }) => {
    const apiInterceptor = new APIInterceptor();
    const wsMonitor = new WebSocketMonitor();

    apiInterceptor.intercept(page);
    wsMonitor.monitor(page);

    console.log('\n========================================');
    console.log('COMPLETE SESSION FLOW E2E TEST');
    console.log('========================================\n');

    // STEP 1: Login
    console.log('Step 1: Login...');
    await loginToJamUI(page, {
      email: 'nuwan@jamkazam.com',
      password: 'jam123',
    });
    await waitForAPICalls(page, 3000);

    const loginCalls = apiInterceptor.getCalls().length;
    console.log(`  ✓ Logged in (${loginCalls} API calls)\n`);

    // Verify we're logged in
    await expect(page).not.toHaveURL(/signin|login/);

    // STEP 2: Navigate to session creation
    console.log('Step 2: Navigate to session creation...');
    apiInterceptor.reset();
    await navigateToSessionCreation(page);
    await waitForAPICalls(page, 2000);

    const navCalls = apiInterceptor.getCalls().length;
    console.log(`  ✓ Navigated to session creation (${navCalls} API calls)\n`);

    // STEP 3: Enable native client and create session
    // STEP 3: Create and join session
    console.log('Step 3: Create and join session...');
    apiInterceptor.reset();
    await fillSessionForm(page, { sessionType: 'private' });
    await waitForAPICalls(page, 8000);

    const sessionCalls = apiInterceptor.getCalls();
    console.log(`  ✓ Session created (${sessionCalls.length} API calls)\n`);

    // Verify session creation endpoints
    const sessionCreation = sessionCalls.find(c =>
      c.method === 'POST' && c.pathname.match(/\/api\/sessions\/?$/)
    );
    expect(sessionCreation).toBeDefined();
    console.log(`  ✓ POST /api/sessions called`);

    const participantAdd = sessionCalls.find(c =>
      c.method === 'POST' && c.pathname.includes('/participants')
    );
    expect(participantAdd).toBeDefined();
    console.log(`  ✓ POST /api/sessions/{id}/participants called`);

    // Extract session ID
    const sessionId = await extractSessionId(page);
    if (sessionId) {
      console.log(`  ✓ Session ID: ${sessionId}`);
    }

    // Verify session interface loaded
    console.log('\nStep 4: Verify session interface...');
    await verifySessionInterfaceLoaded(page);
    console.log(`  ✓ Session interface elements present\n`);

    // Verify WebSocket connections
    const wsVerification = wsMonitor.verifyDualConnections();
    console.log('Step 5: Verify WebSocket connections...');
    console.log(`  Native client: ${wsVerification.hasNativeClient ? 'YES' : 'NO'}`);
    console.log(`  Server: ${wsVerification.hasServerConnection ? 'YES' : 'NO'}`);
    expect(wsVerification.bothEstablished).toBe(true);
    console.log(`  ✓ Dual connections established\n`);

    // Compare with legacy sequence
    console.log('Step 6: Compare with legacy sequence...');
    const expectedPath = path.join(__dirname, '../fixtures/legacy-sequences/complete-flow-simplified.json');
    const expectedCalls = JSON.parse(fs.readFileSync(expectedPath, 'utf8'));

    const allCalls = apiInterceptor.getCalls();
    const comparison = compareAPISequences(allCalls, expectedCalls);

    const matchPercentage = (comparison.matchedCalls / comparison.totalCalls) * 100;
    console.log(`  API calls: ${allCalls.length}`);
    console.log(`  Expected: ${expectedCalls.length}`);
    console.log(`  Match: ${matchPercentage.toFixed(1)}%`);

    // Save comprehensive results
    const resultsDir = path.join(__dirname, '../test-results/e2e');
    if (!fs.existsSync(resultsDir)) {
      fs.mkdirSync(resultsDir, { recursive: true });
    }

    // Save API calls
    fs.writeFileSync(
      path.join(resultsDir, 'complete-flow-api-calls.json'),
      JSON.stringify(allCalls, null, 2)
    );

    // Save comparison report
    fs.writeFileSync(
      path.join(resultsDir, 'complete-flow-comparison.md'),
      comparison.report
    );

    // Save WebSocket data
    fs.writeFileSync(
      path.join(resultsDir, 'complete-flow-websockets.json'),
      wsMonitor.toJSON()
    );

    // Save screenshot
    await page.screenshot({
      path: path.join(resultsDir, 'session-interface.png'),
      fullPage: true,
    });

    console.log('\n========================================');
    console.log('COMPLETE SESSION FLOW TEST: PASSED');
    console.log('========================================\n');

    // Final assertions
    expect(matchPercentage).toBeGreaterThanOrEqual(70);
    expect(wsVerification.bothEstablished).toBe(true);
    expect(sessionCreation).toBeDefined();
    expect(participantAdd).toBeDefined();
  });

  test('session interface has all required controls', async ({ page }) => {
    await loginToJamUI(page);
    await waitForAPICalls(page);

    await navigateToSessionCreation(page);
    await waitForAPICalls(page);

    await fillSessionForm(page);
    await waitForAPICalls(page, 8000);

    // Check for session control buttons
    const expectedControls = [
      'SETTINGS',
      'VOLUME',
      'BROADCAST',
      'RECORD',
      'VIDEO',
      'FILES',
      'RESYNC',
      'LEAVE',
    ];

    const foundControls: string[] = [];
    const missingControls: string[] = [];

    for (const control of expectedControls) {
      const selectors = [
        `text=${control}`,
        `button:has-text("${control}")`,
        `[data-testid="${control.toLowerCase()}"]`,
      ];

      let found = false;
      for (const selector of selectors) {
        try {
          const element = await page.$(selector);
          if (element) {
            foundControls.push(control);
            found = true;
            break;
          }
        } catch {
          continue;
        }
      }

      if (!found) {
        missingControls.push(control);
      }
    }

    console.log('\nSession interface controls:');
    console.log(`  Found: ${foundControls.join(', ')}`);
    if (missingControls.length > 0) {
      console.log(`  Missing: ${missingControls.join(', ')}`);
    }

    // At least some key controls should be present
    expect(foundControls.length).toBeGreaterThan(3);
  });

  test('session creation handles errors gracefully', async ({ page }) => {
    // This test verifies error handling - might fail initially
    const apiInterceptor = new APIInterceptor();
    apiInterceptor.intercept(page);

    await loginToJamUI(page);
    await navigateToSessionCreation(page);
    await page.keyboard.press('Control+Shift+Digit0');
    await waitForAPICalls(page, 3000);

    // Try to create session
    await fillSessionForm(page);
    await waitForAPICalls(page, 8000);

    const calls = apiInterceptor.getCalls();

    // Check if any calls failed
    const failedCalls = calls.filter(c =>
      c.responseStatus && c.responseStatus >= 400
    );

    if (failedCalls.length > 0) {
      console.log('\nFailed API calls:');
      failedCalls.forEach(call => {
        console.log(`  ${call.method} ${call.pathname}: ${call.responseStatus}`);
      });
    }

    // Even if some calls fail, the critical session creation should succeed
    const sessionCreation = calls.find(c =>
      c.method === 'POST' &&
      c.pathname.match(/\/api\/sessions\/?$/) &&
      c.responseStatus &&
      c.responseStatus >= 200 &&
      c.responseStatus < 300
    );

    // Log whether session creation succeeded
    console.log(`\nSession creation: ${sessionCreation ? 'SUCCESS' : 'FAILED'}`);
  });

  test('user can leave session', async ({ page }) => {
    await loginToJamUI(page);
    await waitForAPICalls(page);

    await navigateToSessionCreation(page);
    await waitForAPICalls(page);

    await fillSessionForm(page);
    await waitForAPICalls(page, 8000);

    // Try to find and click LEAVE button
    const leaveSelectors = [
      'text=LEAVE',
      'button:has-text("LEAVE")',
      '[data-testid="leave-button"]',
      'button:has-text("Leave Session")',
    ];

    let leaveClicked = false;
    for (const selector of leaveSelectors) {
      try {
        const element = await page.$(selector);
        if (element) {
          console.log(`\nFound LEAVE button: ${selector}`);
          // Don't actually click it (would end the test), just verify it exists
          leaveClicked = true;
          break;
        }
      } catch {
        continue;
      }
    }

    console.log(`LEAVE button available: ${leaveClicked ? 'YES' : 'NO'}`);
    expect(leaveClicked).toBe(true);
  });
});
