/**
 * E2E Test: Error Scenarios and Validation
 * Tests all error handling, validation, and edge cases
 */

import { test, expect, type Page } from '@playwright/test';

/**
 * Helper: Navigate to booking form step
 */
async function navigateToBookingForm(page: Page) {
  await page.goto('/en/demo');
  await page.waitForTimeout(8000); // Cookie consent

  // Select duration
  await page.getByRole('button', { name: /30 min/i }).click();
  await page.getByRole('button', { name: 'Next' }).click();

  await page.waitForTimeout(1000);

  // Select date and time
  await page.locator('button[data-available="true"]').first().click();
  await page.waitForSelector('button[data-time-slot]');
  await page.locator('button[data-time-slot]').first().click();
  await page.getByRole('button', { name: 'Next' }).click();

  // Now at the booking form
}

test.describe('Error Scenarios and Validation', () => {
  test('should show validation errors for empty required fields', async ({ page }) => {
    await navigateToBookingForm(page);

    // Try to proceed without filling anything
    await page.getByRole('button', { name: 'Next' }).click();

    // Should show multiple validation errors
    await expect(page.getByText(/required|must|enter|fill/i).first()).toBeVisible();

    await page.screenshot({ path: 'test-results/screenshots/error-empty-fields.png' });

    // Count error messages
    const errorMessages = page.locator('[class*="error"], [role="alert"]');
    const errorCount = await errorMessages.count();

    expect(errorCount).toBeGreaterThan(0);
    console.log(`✅ Showed ${errorCount} validation errors for empty fields`);
  });

  test('should validate email format', async ({ page }) => {
    await navigateToBookingForm(page);

    // Fill with valid name and phone
    await page.fill('input[name="fullName"]', 'Test User');
    await page.fill('input[name="telephone"]', '+966501234567');

    // Invalid email formats
    const invalidEmails = [
      'notanemail',
      'missing@domain',
      '@nodomain.com',
      'spaces in@email.com',
      'double@@domain.com',
    ];

    for (const invalidEmail of invalidEmails) {
      await page.fill('input[name="email"]', invalidEmail);
      await page.getByRole('button', { name: 'Next' }).click();

      // Should show email validation error
      await expect(page.getByText(/email|invalid|valid email/i)).toBeVisible({ timeout: 2000 });

      console.log(`✅ Rejected invalid email: ${invalidEmail}`);
      await page.screenshot({
        path: `test-results/screenshots/error-email-${invalidEmail.replace(/[@.]/g, '_')}.png`,
      });
    }
  });

  test('should validate phone number minimum length', async ({ page }) => {
    await navigateToBookingForm(page);

    await page.fill('input[name="fullName"]', 'Test User');
    await page.fill('input[name="email"]', 'valid@email.com');

    // Too short phone numbers
    const invalidPhones = [
      '+123',
      '+96650',
      '12345',
      '+971',
    ];

    for (const invalidPhone of invalidPhones) {
      await page.fill('input[name="telephone"]', invalidPhone);
      await page.getByRole('button', { name: 'Next' }).click();

      // Should show phone validation error
      await expect(page.getByText(/phone|telephone|6 digits|invalid/i)).toBeVisible({ timeout: 2000 });

      console.log(`✅ Rejected phone < 6 digits: ${invalidPhone}`);
    }

    await page.screenshot({ path: 'test-results/screenshots/error-phone-too-short.png' });
  });

  test('should validate full name requirement', async ({ page }) => {
    await navigateToBookingForm(page);

    await page.fill('input[name="email"]', 'valid@email.com');
    await page.fill('input[name="telephone"]', '+966501234567');

    // Leave name empty
    await page.fill('input[name="fullName"]', '');
    await page.getByRole('button', { name: 'Next' }).click();

    // Should show name validation error
    await expect(page.getByText(/name|required/i)).toBeVisible();

    await page.screenshot({ path: 'test-results/screenshots/error-name-required.png' });
  });

  test('should prevent proceeding without selecting duration', async ({ page }) => {
    await page.goto('/en/demo');
    await page.waitForTimeout(8000);

    // Try to proceed without selecting duration
    await page.getByRole('button', { name: 'Next' }).click();

    // Should show duration selection error
    await expect(page.getByText(/duration|select|choose/i)).toBeVisible({ timeout: 2000 });

    await page.screenshot({ path: 'test-results/screenshots/error-no-duration.png' });

    // Should stay on step 1
    await expect(page.locator('[data-step="1"][data-current="true"]')).toBeVisible();
  });

  test('should prevent proceeding without selecting date', async ({ page }) => {
    await page.goto('/en/demo');
    await page.waitForTimeout(8000);

    // Select duration
    await page.getByRole('button', { name: /30 min/i }).click();
    await page.getByRole('button', { name: 'Next' }).click();

    await page.waitForTimeout(1000);

    // Try to proceed without selecting date
    await page.getByRole('button', { name: 'Next' }).click();

    // Should show date selection error
    await expect(page.getByText(/date|select|choose/i)).toBeVisible({ timeout: 2000 });

    await page.screenshot({ path: 'test-results/screenshots/error-no-date.png' });
  });

  test('should prevent proceeding without selecting time', async ({ page }) => {
    await page.goto('/en/demo');
    await page.waitForTimeout(8000);

    await page.getByRole('button', { name: /30 min/i }).click();
    await page.getByRole('button', { name: 'Next' }).click();

    await page.waitForTimeout(1000);

    // Select date only
    await page.locator('button[data-available="true"]').first().click();

    // Try to proceed without selecting time
    await page.getByRole('button', { name: 'Next' }).click();

    // Should show time selection error
    await expect(page.getByText(/time|select|choose/i)).toBeVisible({ timeout: 2000 });

    await page.screenshot({ path: 'test-results/screenshots/error-no-time.png' });
  });

  test('should show API error when booking fails', async ({ page }) => {
    // Mock API failure
    await page.route('**/api/demo/book', async (route) => {
      await route.fulfill({
        status: 500,
        contentType: 'application/json',
        body: JSON.stringify({
          error: 'Database connection failed',
          message: 'Unable to process booking',
        }),
      });
    });

    await navigateToBookingForm(page);

    // Fill form completely
    await page.fill('input[name="fullName"]', 'API Error Test');
    await page.fill('input[name="email"]', 'api.error@test.com');
    await page.fill('input[name="telephone"]', '+966501234567');
    await page.fill('textarea[name="message"]', 'Testing API error');
    await page.getByRole('button', { name: 'Next' }).click();

    // Confirm booking
    await page.getByRole('button', { name: /Confirm Booking/i }).click();

    // Should show error message in red box
    await expect(page.locator('[class*="error"], [role="alert"]')).toBeVisible({ timeout: 10000 });
    await expect(page.getByText(/error|failed|unable/i)).toBeVisible();

    await page.screenshot({ path: 'test-results/screenshots/error-api-failure.png' });

    // Should stay on confirmation page
    await expect(page.locator('[data-step="4"]')).toBeVisible();
  });

  test('should handle network timeout gracefully', async ({ page }) => {
    // Mock slow API (timeout)
    await page.route('**/api/demo/book', async (route) => {
      // Delay much longer than expected
      await new Promise(resolve => setTimeout(resolve, 30000));
      await route.fulfill({
        status: 504,
        body: JSON.stringify({ error: 'Gateway timeout' }),
      });
    });

    await navigateToBookingForm(page);

    await page.fill('input[name="fullName"]', 'Timeout Test');
    await page.fill('input[name="email"]', 'timeout@test.com');
    await page.fill('input[name="telephone"]', '+966501234567');
    await page.getByRole('button', { name: 'Next' }).click();

    const confirmButton = page.getByRole('button', { name: /Confirm Booking/i });
    await confirmButton.click();

    // Should show loading state
    await expect(page.getByText(/Submitting/i)).toBeVisible({ timeout: 2000 });

    // After timeout, should show error
    await expect(page.getByText(/error|timeout|failed/i)).toBeVisible({ timeout: 35000 });

    await page.screenshot({ path: 'test-results/screenshots/error-timeout.png' });
  });

  test('should sanitize XSS attempts in message field', async ({ page }) => {
    await navigateToBookingForm(page);

    const xssAttempts = [
      '<script>alert("xss")</script>',
      '<img src=x onerror="alert(1)">',
      'javascript:alert(1)',
      '<iframe src="evil.com">',
    ];

    for (const xssAttempt of xssAttempts) {
      await page.fill('input[name="fullName"]', 'XSS Test User');
      await page.fill('input[name="email"]', 'xss@test.com');
      await page.fill('input[name="telephone"]', '+966501234567');
      await page.fill('textarea[name="message"]', xssAttempt);

      await page.getByRole('button', { name: 'Next' }).click();

      // Should proceed (backend sanitizes)
      await expect(page.locator('[data-step="4"]')).toBeVisible({ timeout: 5000 });

      console.log(`✅ XSS attempt handled: ${xssAttempt.substring(0, 30)}...`);

      // Go back for next test
      await page.getByRole('button', { name: /Back/i }).click();
    }

    await page.screenshot({ path: 'test-results/screenshots/error-xss-handled.png' });
  });

  test('should handle very long input strings', async ({ page }) => {
    await navigateToBookingForm(page);

    const longString = 'A'.repeat(1000);

    await page.fill('input[name="fullName"]', longString.substring(0, 100));
    await page.fill('input[name="email"]', 'long@test.com');
    await page.fill('input[name="telephone"]', '+966501234567');
    await page.fill('textarea[name="message"]', longString);

    await page.screenshot({ path: 'test-results/screenshots/error-long-input.png' });

    // Should either truncate or show validation error
    await page.getByRole('button', { name: 'Next' }).click();

    // Either proceeds (with truncation) or shows error
    const hasError = await page.locator('[class*="error"]').count() > 0;
    const isOnStep4 = await page.locator('[data-step="4"]').isVisible();

    expect(hasError || isOnStep4).toBe(true);
    console.log(`✅ Long input handled: ${hasError ? 'showed error' : 'truncated'}`);
  });

  test('should show clear error messages in red box', async ({ page }) => {
    await navigateToBookingForm(page);

    // Trigger validation error
    await page.fill('input[name="email"]', 'invalid-email');
    await page.getByRole('button', { name: 'Next' }).click();

    // Find error element
    const errorBox = page.locator('[class*="error"], [class*="red"], [role="alert"]').first();

    if (await errorBox.isVisible()) {
      // Check that it's styled as an error (red background or border)
      const backgroundColor = await errorBox.evaluate((el) => {
        const styles = window.getComputedStyle(el);
        return styles.backgroundColor || styles.borderColor;
      });

      console.log(`Error box styling: ${backgroundColor}`);

      // Take screenshot to verify visual appearance
      await page.screenshot({ path: 'test-results/screenshots/error-red-box.png' });

      // Error message should be clear and visible
      await expect(errorBox).toContainText(/email|invalid|valid/i);
    }
  });

  test('should handle rapid form submissions (prevent double-submit)', async ({ page }) => {
    await navigateToBookingForm(page);

    await page.fill('input[name="fullName"]', 'Rapid Submit Test');
    await page.fill('input[name="email"]', 'rapid@test.com');
    await page.fill('input[name="telephone"]', '+966501234567');
    await page.getByRole('button', { name: 'Next' }).click();

    const confirmButton = page.getByRole('button', { name: /Confirm Booking/i });

    // Click multiple times rapidly
    await confirmButton.click();
    await confirmButton.click();
    await confirmButton.click();

    // Button should be disabled after first click
    await expect(confirmButton).toBeDisabled({ timeout: 1000 });

    console.log(`✅ Multiple clicks prevented by disabled button`);

    await page.screenshot({ path: 'test-results/screenshots/error-double-submit-prevented.png' });

    // Wait for success or error
    await page.waitForTimeout(5000);
  });

  test('should validate special characters in name', async ({ page }) => {
    await navigateToBookingForm(page);

    const namesWithSpecialChars = [
      'Test <User>',
      'Test "User"',
      "Test 'User'",
      'Test & User',
    ];

    for (const name of namesWithSpecialChars) {
      await page.fill('input[name="fullName"]', name);
      await page.fill('input[name="email"]', 'special@test.com');
      await page.fill('input[name="telephone"]', '+966501234567');
      await page.getByRole('button', { name: 'Next' }).click();

      // Should either proceed or show validation error
      const hasError = await page.locator('[class*="error"]').count() > 0;
      const isOnStep4 = await page.locator('[data-step="4"]').isVisible();

      expect(hasError || isOnStep4).toBe(true);

      console.log(`Special char name handled: ${name}`);

      if (!isOnStep4) {
        // Had error, clear for next test
        await page.fill('input[name="fullName"]', '');
      } else {
        // Proceeded, go back
        await page.getByRole('button', { name: /Back/i }).click();
      }
    }
  });

  test('should show loading indicator while fetching time slots', async ({ page }) => {
    await page.goto('/en/demo');
    await page.waitForTimeout(8000);

    await page.getByRole('button', { name: /30 min/i }).click();
    await page.getByRole('button', { name: 'Next' }).click();

    await page.waitForTimeout(500);

    // Click a date
    await page.locator('button[data-available="true"]').first().click();

    // Should show loading indicator
    const loadingIndicator = page.locator('[class*="loading"], [class*="spinner"], [aria-busy="true"]');

    if (await loadingIndicator.isVisible({ timeout: 1000 })) {
      console.log(`✅ Loading indicator shown while fetching slots`);
      await page.screenshot({ path: 'test-results/screenshots/error-loading-indicator.png' });
    }

    // Eventually time slots should appear
    await expect(page.locator('button[data-time-slot]')).toBeVisible({ timeout: 10000 });
  });
});
