/**
 * E2E Test for Interview Booking Flow (Applicant Perspective)
 *
 * Tests complete user journey from receiving email to booking interview
 */

import { test, expect } from '@playwright/test';
import { prisma } from '../../lib/db';
import jwt from 'jsonwebtoken';

const BASE_URL = 'http://localhost:9000';

test.describe('Interview Booking Flow E2E', () => {
  let testToken: string;
  let testApplicationId: string;
  let testJobId: string;

  test.beforeAll(async () => {
    // Create test job
    const job = await prisma.jobs.create({
      data: {
        title: 'E2E Test Engineer',
        titleAr: 'مهندس اختبارات',
        department: 'Engineering',
        location: 'Doha, Qatar',
        description: 'Test job for E2E testing',
        descriptionAr: 'وظيفة اختبار',
        status: 'open',
      },
    });
    testJobId = job.id;

    // Create test application
    const application = await prisma.job_applications.create({
      data: {
        jobId: testJobId,
        applicantName: 'E2E Test User',
        applicantEmail: 'e2e-test@example.com',
        phoneNumber: '+97150999999',
        cvUrl: 'https://example.com/cv.pdf',
        status: 'selected',
      },
    });
    testApplicationId = application.id;

    // Generate valid token
    const payload = {
      applicationId: testApplicationId,
      jobId: testJobId,
      applicantEmail: 'e2e-test@example.com',
      iat: Math.floor(Date.now() / 1000),
      exp: Math.floor(Date.now() / 1000) + 3 * 24 * 60 * 60,
      jti: 'e2e-test-token',
    };

    testToken = jwt.sign(payload, process.env.INTERVIEW_TOKEN_SECRET || 'test-secret', {
      algorithm: 'HS256',
    });

    // Store token in database
    await prisma.interview_booking_tokens.create({
      data: {
        id: 'e2e-test-token',
        token: testToken,
        applicationId: testApplicationId,
        jobId: testJobId,
        applicantEmail: 'e2e-test@example.com',
        expiresAt: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
        isRevoked: false,
      },
    });
  });

  test.afterAll(async () => {
    // Cleanup
    await prisma.interview_bookings.deleteMany({
      where: { applicationId: testApplicationId },
    });
    await prisma.interview_booking_tokens.deleteMany({
      where: { applicationId: testApplicationId },
    });
    await prisma.job_applications.deleteMany({
      where: { id: testApplicationId },
    });
    await prisma.jobs.deleteMany({
      where: { id: testJobId },
    });
  });

  test('should complete interview booking with valid token', async ({ page }) => {
    // Navigate to booking page with token
    await page.goto(`${BASE_URL}/en/careers/interview/schedule?token=${testToken}`);

    // Wait for page to load
    await expect(page.locator('h1')).toContainText('Schedule Your Interview');

    // Verify job information displayed
    await expect(page.locator('text=E2E Test Engineer')).toBeVisible();

    // Select a date (7 days from now, not weekend)
    const futureDate = new Date();
    let daysToAdd = 7;
    futureDate.setDate(futureDate.getDate() + daysToAdd);
    
    // Skip to Monday if it's a weekend
    while (futureDate.getDay() === 0 || futureDate.getDay() === 6) {
      daysToAdd++;
      futureDate.setDate(new Date().getDate() + daysToAdd);
    }

    const dateString = futureDate.toISOString().split('T')[0];
    await page.fill('input[type="date"]', dateString);

    // Select time slot
    await page.selectOption('select[name="time"]', '10:00');

    // Fill optional notes
    await page.fill('textarea[name="notes"]', 'Prefer morning slot. Looking forward to the interview.');

    // Submit booking
    await page.click('button[type="submit"]');

    // Wait for success message
    await expect(page.locator('text=/Interview booking confirmed/i')).toBeVisible({ timeout: 10000 });

    // Verify booking in database
    const booking = await prisma.interview_bookings.findFirst({
      where: { applicationId: testApplicationId },
    });

    expect(booking).toBeDefined();
    expect(booking?.status).toBe('pending');
    expect(booking?.preferredTime).toBe('10:00:00');
  });

  test('should show error for expired token', async ({ page }) => {
    // Create expired token
    const expiredPayload = {
      applicationId: testApplicationId,
      jobId: testJobId,
      applicantEmail: 'e2e-test@example.com',
      iat: Math.floor(Date.now() / 1000) - 4 * 24 * 60 * 60,
      exp: Math.floor(Date.now() / 1000) - 24 * 60 * 60,
      jti: 'expired-token',
    };

    const expiredToken = jwt.sign(expiredPayload, process.env.INTERVIEW_TOKEN_SECRET || 'test-secret', {
      algorithm: 'HS256',
    });

    await page.goto(`${BASE_URL}/en/careers/interview/schedule?token=${expiredToken}`);

    // Should show error message
    await expect(page.locator('text=/expired/i')).toBeVisible({ timeout: 5000 });
  });

  test('should validate date selection (no weekends)', async ({ page }) => {
    await page.goto(`${BASE_URL}/en/careers/interview/schedule?token=${testToken}`);

    // Try to select a Saturday
    const nextSaturday = new Date();
    nextSaturday.setDate(nextSaturday.getDate() + ((6 - nextSaturday.getDay() + 7) % 7 || 7));
    const saturdayString = nextSaturday.toISOString().split('T')[0];

    await page.fill('input[type="date"]', saturdayString);
    await page.selectOption('select[name="time"]', '10:00');
    await page.click('button[type="submit"]');

    // Should show weekend error
    await expect(page.locator('text=/weekend/i')).toBeVisible({ timeout: 5000 });
  });

  test('should validate time slots (business hours only)', async ({ page }) => {
    await page.goto(`${BASE_URL}/en/careers/interview/schedule?token=${testToken}`);

    // Check time dropdown only has business hours
    const timeOptions = await page.locator('select[name="time"] option').allTextContents();
    
    // Should not include early morning or late evening
    expect(timeOptions).not.toContain('08:00');
    expect(timeOptions).not.toContain('17:00');
    
    // Should include business hours
    expect(timeOptions).toContain('09:00');
    expect(timeOptions).toContain('16:30');
  });
});
