import { chromium } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';

/**
 * Detailed step-by-step verification of the session join flow
 * This script goes through each step individually and captures API calls at each stage
 */

interface StepCapture {
  stepNumber: number;
  stepName: string;
  apiCalls: any[];
  wsMessages: any[];
  screenshots: string[];
  timestamp: string;
}

async function verifySessionFlow() {
  console.log('='.repeat(80));
  console.log('SESSION FLOW STEP-BY-STEP VERIFICATION');
  console.log('='.repeat(80));
  console.log();

  const browser = await chromium.launch({
    headless: false,
    slowMo: 800,
  });

  const testResultsDir = path.join(__dirname, '../test-results/step-verification');
  if (!fs.existsSync(testResultsDir)) {
    fs.mkdirSync(testResultsDir, { recursive: true });
  }

  const context = await browser.newContext({
    ignoreHTTPSErrors: true,
  });

  const page = await context.newPage();

  const stepCaptures: StepCapture[] = [];
  let currentStepApiCalls: any[] = [];
  let currentStepWsMessages: any[] = [];

  // Listen to all network activity
  page.on('request', request => {
    const url = request.url();
    if (url.includes('/api/')) {
      currentStepApiCalls.push({
        type: 'request',
        method: request.method(),
        url: url,
        timestamp: new Date().toISOString(),
      });
      console.log(`  [API] ${request.method()} ${url}`);
    }
  });

  page.on('response', async response => {
    const url = response.url();
    if (url.includes('/api/')) {
      let body = null;
      try {
        const contentType = response.headers()['content-type'] || '';
        if (contentType.includes('application/json')) {
          body = await response.json();
        }
      } catch (e) {
        // Ignore
      }

      currentStepApiCalls.push({
        type: 'response',
        status: response.status(),
        url: url,
        body: body,
        timestamp: new Date().toISOString(),
      });
    }
  });

  page.on('websocket', ws => {
    console.log(`  [WebSocket] Connected: ${ws.url()}`);
    currentStepWsMessages.push({
      event: 'open',
      url: ws.url(),
      timestamp: new Date().toISOString(),
    });

    ws.on('framesent', frame => {
      currentStepWsMessages.push({
        event: 'sent',
        payload: frame.payload.toString().substring(0, 200),
        timestamp: new Date().toISOString(),
      });
    });

    ws.on('framereceived', frame => {
      currentStepWsMessages.push({
        event: 'received',
        payload: frame.payload.toString().substring(0, 200),
        timestamp: new Date().toISOString(),
      });
    });
  });

  function saveStepCapture(stepNumber: number, stepName: string) {
    const capture: StepCapture = {
      stepNumber,
      stepName,
      apiCalls: [...currentStepApiCalls],
      wsMessages: [...currentStepWsMessages],
      screenshots: [],
      timestamp: new Date().toISOString(),
    };

    stepCaptures.push(capture);

    // Save individual step data
    const stepDir = path.join(testResultsDir, `step-${stepNumber}`);
    if (!fs.existsSync(stepDir)) {
      fs.mkdirSync(stepDir, { recursive: true });
    }

    fs.writeFileSync(
      path.join(stepDir, 'api-calls.json'),
      JSON.stringify(currentStepApiCalls, null, 2)
    );

    fs.writeFileSync(
      path.join(stepDir, 'ws-messages.json'),
      JSON.stringify(currentStepWsMessages, null, 2)
    );

    console.log(`  ✓ Captured ${currentStepApiCalls.length} API calls`);
    console.log(`  ✓ Captured ${currentStepWsMessages.length} WebSocket messages`);

    // Reset for next step
    currentStepApiCalls = [];
    currentStepWsMessages = [];
  }

  try {
    // STEP 1: User Authentication
    console.log('\n' + '='.repeat(80));
    console.log('STEP 1: USER AUTHENTICATION');
    console.log('='.repeat(80));

    console.log('Navigating to signin page...');
    await page.goto('http://www.jamkazam.local:3100/signin', {
      waitUntil: 'networkidle',
      timeout: 30000,
    });

    await page.screenshot({
      path: path.join(testResultsDir, 'step-1-signin-page.png'),
      fullPage: true,
    });

    console.log('Filling in credentials...');
    await page.fill('input#session_email', 'nuwan@jamkazam.com');
    await page.fill('input#session_password', 'jam123');

    console.log('Clicking sign in...');
    await page.click('input[type="submit"]');

    console.log('Waiting for login to complete...');
    await page.waitForLoadState('networkidle', { timeout: 15000 }).catch(() => {});
    await page.waitForTimeout(3000);

    await page.screenshot({
      path: path.join(testResultsDir, 'step-1-after-login.png'),
      fullPage: true,
    });

    saveStepCapture(1, 'User Authentication');

    // STEP 2: Dashboard Load
    console.log('\n' + '='.repeat(80));
    console.log('STEP 2: DASHBOARD LOAD');
    console.log('='.repeat(80));

    console.log('Dashboard is loading (WebSocket connection should establish)...');
    await page.waitForTimeout(5000); // Wait for all dashboard data to load

    await page.screenshot({
      path: path.join(testResultsDir, 'step-2-dashboard-loaded.png'),
      fullPage: true,
    });

    saveStepCapture(2, 'Dashboard Load');

    // STEP 3: Skip Upgrade Modal
    console.log('\n' + '='.repeat(80));
    console.log('STEP 3: SKIP UPGRADE MODAL');
    console.log('='.repeat(80));

    console.log('Pressing Cmd+Shift+0 to dismiss upgrade modal...');
    await page.keyboard.press('Meta+Shift+Digit0');
    await page.waitForTimeout(2000);

    // Check if overlay still exists and try to dismiss it
    const overlay = await page.$('.dialog-overlay');
    if (overlay) {
      console.log('Overlay still present, trying to click it or escape...');
      await page.keyboard.press('Escape');
      await page.waitForTimeout(1000);

      // If still there, try clicking outside
      const overlayStill = await page.$('.dialog-overlay');
      if (overlayStill) {
        console.log('Trying to force-remove overlay...');
        await page.evaluate(() => {
          const overlays = document.querySelectorAll('.dialog-overlay');
          overlays.forEach(o => o.remove());
        });
        await page.waitForTimeout(500);
      }
    }

    await page.screenshot({
      path: path.join(testResultsDir, 'step-3-modal-dismissed.png'),
      fullPage: true,
    });

    saveStepCapture(3, 'Skip Upgrade Modal');

    // STEP 4: Navigate to Create Session
    console.log('\n' + '='.repeat(80));
    console.log('STEP 4: NAVIGATE TO CREATE SESSION');
    console.log('='.repeat(80));

    console.log('Looking for Create Session button...');

    // Remove any remaining overlays
    await page.evaluate(() => {
      const overlays = document.querySelectorAll('.dialog-overlay');
      overlays.forEach(o => o.remove());
    });
    await page.waitForTimeout(500);

    // Try multiple selectors
    const createSessionSelectors = [
      'text=create session',
      'h2:has-text("create session")',
      '[data-testid="create-session"]',
      'button:has-text("Create Session")',
      'a:has-text("Create Session")',
      'div:has-text("Create Session")',
      '.tile:has-text("Create Session")',
      '[title*="Create Session"]',
    ];

    let sessionClicked = false;
    for (const selector of createSessionSelectors) {
      try {
        const element = await page.$(selector);
        if (element) {
          console.log(`Found Create Session using: ${selector}`);
          // Use force click to bypass any remaining overlays
          await page.click(selector, { force: true });
          sessionClicked = true;
          break;
        }
      } catch (e) {
        console.log(`Selector ${selector} failed: ${e.message}`);
        continue;
      }
    }

    if (!sessionClicked) {
      console.warn('Could not find "Create Session" button - saving partial results...');
    }

    await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
    await page.waitForTimeout(2000);

    await page.screenshot({
      path: path.join(testResultsDir, 'step-4-session-page.png'),
      fullPage: true,
    });

    saveStepCapture(4, 'Navigate to Create Session');

    // STEP 5: Create Quick Start Session
    console.log('\n' + '='.repeat(80));
    console.log('STEP 5: CREATE QUICK START SESSION');
    console.log('='.repeat(80));

    console.log('Pressing Ctrl+Shift+0 to enable native client features...');
    await page.keyboard.press('Control+Shift+Digit0');
    await page.waitForTimeout(2000);

    await page.screenshot({
      path: path.join(testResultsDir, 'step-5-before-quickstart.png'),
      fullPage: true,
    });

    console.log('Looking for Quick Start button...');
    const quickStartSelectors = [
      'text=QUICK START PRIVATE',
      'text=QUICK START PUBLIC',
      'text=QUICK START FRIENDS',
      'button:has-text("QUICK START")',
      'button:has-text("Quick Start")',
      '[data-testid="quick-start"]',
    ];

    let quickStartClicked = false;
    for (const selector of quickStartSelectors) {
      try {
        const element = await page.$(selector);
        if (element) {
          console.log(`Found Quick Start button using: ${selector}`);
          await page.click(selector, { force: true });
          quickStartClicked = true;
          console.log('Quick Start button clicked!');
          break;
        }
      } catch (e) {
        console.log(`Selector ${selector} failed: ${e.message}`);
        continue;
      }
    }

    if (!quickStartClicked) {
      console.warn('Could not find Quick Start button - trying generic button click');
      // Try to click any button with "QUICK START" text
      try {
        await page.evaluate(() => {
          const buttons = Array.from(document.querySelectorAll('button'));
          const quickStartBtn = buttons.find(btn => btn.textContent?.includes('QUICK START'));
          if (quickStartBtn) {
            (quickStartBtn as HTMLElement).click();
            return true;
          }
          return false;
        });
        console.log('Clicked Quick Start via evaluate');
        quickStartClicked = true;
      } catch (e) {
        console.error('Failed to click Quick Start button');
      }
    }

    console.log('Waiting for session to initialize...');
    await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
    await page.waitForTimeout(5000); // Wait for WebSocket messages

    await page.screenshot({
      path: path.join(testResultsDir, 'step-5-session-joined.png'),
      fullPage: true,
    });

    saveStepCapture(5, 'Create Quick Start Session');

    // Generate summary report
    console.log('\n' + '='.repeat(80));
    console.log('GENERATING SUMMARY REPORT');
    console.log('='.repeat(80));

    const report = generateReport(stepCaptures);
    fs.writeFileSync(path.join(testResultsDir, 'VERIFICATION_REPORT.md'), report);
    console.log(`✓ Report saved to: ${testResultsDir}/VERIFICATION_REPORT.md`);

    // Save complete capture
    fs.writeFileSync(
      path.join(testResultsDir, 'complete-capture.json'),
      JSON.stringify(stepCaptures, null, 2)
    );

    console.log('\nKeeping browser open for 10 seconds for inspection...');
    await page.waitForTimeout(10000);

  } catch (error) {
    console.error('\n❌ Error during verification:', error);
    await page.screenshot({
      path: path.join(testResultsDir, 'error-screenshot.png'),
      fullPage: true,
    });
    throw error;
  } finally {
    await context.close();
    await browser.close();
  }
}

function generateReport(stepCaptures: StepCapture[]): string {
  let report = `# Session Flow Verification Report

**Generated:** ${new Date().toLocaleString()}

## Summary

This report documents the exact API calls and WebSocket messages that occur at each step of the session join flow.

`;

  for (const step of stepCaptures) {
    const apiRequests = step.apiCalls.filter(c => c.type === 'request');
    const uniqueEndpoints = new Set(
      apiRequests.map(c => `${c.method} ${new URL(c.url).pathname}`)
    );

    report += `
## Step ${step.stepNumber}: ${step.stepName}

**Timestamp:** ${step.timestamp}

### API Calls Made (${apiRequests.length} requests)

`;

    if (uniqueEndpoints.size > 0) {
      report += 'Unique endpoints called:\n';
      for (const endpoint of Array.from(uniqueEndpoints)) {
        const count = apiRequests.filter(
          c => `${c.method} ${new URL(c.url).pathname}` === endpoint
        ).length;
        report += `- ${endpoint}${count > 1 ? ` (${count} times)` : ''}\n`;
      }
    } else {
      report += 'No API calls made during this step.\n';
    }

    report += `
### WebSocket Activity

- Total messages sent/received: ${step.wsMessages.length}
- WebSocket connection events: ${step.wsMessages.filter(m => m.event === 'open').length}

`;

    report += `
### Screenshots

- Available at: \`step-${step.stepNumber}/\`

---

`;
  }

  // Add comparison section
  report += `
## Key Findings

### Step-by-Step API Call Summary

`;

  for (const step of stepCaptures) {
    const apiRequests = step.apiCalls.filter(c => c.type === 'request');
    report += `**Step ${step.stepNumber} (${step.stepName}):** ${apiRequests.length} API calls\n`;
  }

  report += `

### WebSocket Message Summary

`;

  for (const step of stepCaptures) {
    report += `**Step ${step.stepNumber} (${step.stepName}):** ${step.wsMessages.length} messages\n`;
  }

  report += `

## Recommendations

Based on this verification:

1. Review the API calls at each step to ensure the migration plan accurately reflects them
2. Pay special attention to Step 5 (Create Quick Start Session) - this is where session creation happens
3. Verify WebSocket message sequences match between legacy and new implementation
4. Check if removing the separate "trick browser" step changed any API behavior

## Next Steps

1. Compare this capture with the original capture to identify any differences
2. Update the migration plan if any discrepancies are found
3. Use these findings to create more accurate Playwright tests
`;

  return report;
}

// Run the verification
verifySessionFlow()
  .then(() => {
    console.log('\n✅ Verification completed successfully!');
    process.exit(0);
  })
  .catch(error => {
    console.error('\n❌ Verification failed:', error);
    process.exit(1);
  });
