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

/**
 * Newsletter Subscription E2E Tests
 * Tests the newsletter form in the footer across all pages
 * - Happy path subscription
 * - Validation (empty, invalid email)
 * - Loading states
 * - Error handling (network, server)
 * - Rate limiting behavior
 * - Accessibility
 */

test.describe('Newsletter Subscription - Form Presence', () => {
  const pagesWithNewsletter = [
    { path: '/', name: 'Homepage' },
    { path: '/about', name: 'About' },
    { path: '/services', name: 'Services' },
    { path: '/blog', name: 'Blog' },
    { path: '/contact', name: 'Contact' },
  ];

  for (const pg of pagesWithNewsletter) {
    test(`newsletter form is present on ${pg.name}`, async ({ page }) => {
      await page.goto(pg.path);
      await page.waitForLoadState('domcontentloaded');

      const form = page.locator('#newsletter-form');
      await expect(form).toBeVisible();

      const emailInput = page.locator('#newsletter-email');
      await expect(emailInput).toBeVisible();

      const submitButton = form.locator('button[type="submit"]');
      await expect(submitButton).toBeVisible();
    });
  }
});

test.describe('Newsletter Subscription - Happy Path', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/');
    await page.waitForLoadState('networkidle');
    // Scroll to footer where newsletter form is
    await page.locator('footer').scrollIntoViewIfNeeded();
  });

  test('valid email subscription shows success message', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');
    const messageEl = page.locator('#newsletter-message');

    await emailInput.fill('subscriber@example.com');
    await submitButton.click();

    // Message should appear
    await expect(messageEl).not.toHaveClass(/hidden/, { timeout: 10000 });
    const messageText = await messageEl.textContent();
    expect(messageText).toBeTruthy();
    expect(messageText!.length).toBeGreaterThan(0);
  });

  test('form resets after successful subscription', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');

    await emailInput.fill('reset.test@example.com');
    await submitButton.click();

    // Wait for response
    await page.waitForTimeout(3000);

    // Check if message is shown (success or configured error)
    const messageEl = page.locator('#newsletter-message');
    const isVisible = await messageEl.evaluate((el) => !el.classList.contains('hidden'));

    // If successful, form should be reset
    if (isVisible) {
      const messageText = await messageEl.textContent();
      if (messageText?.toLowerCase().includes('subscrib') || messageText?.toLowerCase().includes('thanks')) {
        await expect(emailInput).toHaveValue('');
      }
    }
  });

  test('submit button shows loading state during submission', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');

    await emailInput.fill('loading.test@example.com');
    await submitButton.click();

    // Button should be disabled during submission
    await expect(submitButton).toBeDisabled();
  });

  test('submit button re-enables after submission completes', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');

    await emailInput.fill('reenable.test@example.com');
    await submitButton.click();

    // Wait for the submission to complete
    await page.waitForTimeout(4000);

    // Button should be re-enabled
    await expect(submitButton).toBeEnabled();
  });
});

test.describe('Newsletter Subscription - Validation', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/');
    await page.locator('footer').scrollIntoViewIfNeeded();
  });

  test('email field is required - HTML5 validation', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');

    // Submit without email
    await submitButton.click();

    // HTML5 required validation should prevent submission
    const isInvalid = await emailInput.evaluate((el: HTMLInputElement) => !el.checkValidity());
    expect(isInvalid).toBeTruthy();
  });

  test('email field rejects invalid email format - HTML5', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');

    await emailInput.fill('not-an-email');
    await submitButton.click();

    // HTML5 type="email" should reject non-email
    const isInvalid = await emailInput.evaluate((el: HTMLInputElement) => !el.checkValidity());
    expect(isInvalid).toBeTruthy();
  });

  test('email field accepts valid email format', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');

    const validEmails = [
      'user@example.com',
      'user.name+tag@example.co.uk',
      'user123@subdomain.domain.org',
    ];

    for (const email of validEmails) {
      await emailInput.fill(email);
      const isValid = await emailInput.evaluate((el: HTMLInputElement) => el.checkValidity());
      expect(isValid).toBeTruthy();
    }
  });

  test('email field has correct input type', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const inputType = await emailInput.getAttribute('type');
    expect(inputType).toBe('email');
  });

  test('email field has autocomplete attribute', async ({ page }) => {
    const emailInput = page.locator('#newsletter-email');
    const autocomplete = await emailInput.getAttribute('autocomplete');
    expect(autocomplete).toBe('email');
  });
});

test.describe('Newsletter Subscription - API Integration', () => {
  test('newsletter API endpoint responds to valid subscription', async ({ request }) => {
    const response = await request.post('/api/newsletter', {
      headers: { 'Content-Type': 'application/json' },
      data: { email: 'api.test@example.com' },
    });

    // Should be 200 (success) or 429 (rate limited in test env)
    expect([200, 429]).toContain(response.status());

    if (response.status() === 200) {
      const body = await response.json() as { success: boolean; message?: string };
      expect(body.success).toBe(true);
      expect(body.message).toBeTruthy();
    }
  });

  test('newsletter API rejects invalid email', async ({ request }) => {
    const response = await request.post('/api/newsletter', {
      headers: { 'Content-Type': 'application/json' },
      data: { email: 'invalid-email' },
    });

    expect(response.status()).toBe(422);
    const body = await response.json() as { success: boolean; error: string };
    expect(body.success).toBe(false);
    expect(body.error).toBeTruthy();
  });

  test('newsletter API rejects empty email', async ({ request }) => {
    const response = await request.post('/api/newsletter', {
      headers: { 'Content-Type': 'application/json' },
      data: { email: '' },
    });

    expect(response.status()).toBe(422);
    const body = await response.json() as { success: boolean; error: string };
    expect(body.success).toBe(false);
  });

  test('newsletter API returns rate limit headers', async ({ request }) => {
    const response = await request.post('/api/newsletter', {
      headers: { 'Content-Type': 'application/json' },
      data: { email: 'ratelimit.headers@example.com' },
    });

    const headers = response.headers();
    expect(headers['x-ratelimit-limit']).toBeDefined();
    expect(headers['x-ratelimit-remaining']).toBeDefined();
    expect(headers['x-ratelimit-reset']).toBeDefined();
  });

  test('newsletter API accepts form-encoded data', async ({ request }) => {
    const response = await request.post('/api/newsletter', {
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      form: { email: 'formencoded@example.com' },
    });

    // Should be 200 or 429 (not 400 bad request)
    expect([200, 429]).toContain(response.status());
  });
});

test.describe('Newsletter Subscription - Network Error Handling', () => {
  test('newsletter form shows error on network failure', async ({ page }) => {
    await page.goto('/');
    await page.locator('footer').scrollIntoViewIfNeeded();

    // Intercept the API call and make it fail
    await page.route('/api/newsletter', async (route) => {
      await route.abort('failed');
    });

    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');
    const messageEl = page.locator('#newsletter-message');

    await emailInput.fill('network.error@example.com');
    await submitButton.click();

    // Should show error message
    await expect(messageEl).not.toHaveClass(/hidden/, { timeout: 5000 });
    const messageText = await messageEl.textContent();
    expect(messageText?.toLowerCase()).toMatch(/network|error|check/);
  });

  test('newsletter form shows server error response', async ({ page }) => {
    await page.goto('/');
    await page.locator('footer').scrollIntoViewIfNeeded();

    // Intercept and return server error
    await page.route('/api/newsletter', async (route) => {
      await route.fulfill({
        status: 500,
        contentType: 'application/json',
        body: JSON.stringify({ success: false, error: 'Server temporarily unavailable.' }),
      });
    });

    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');
    const messageEl = page.locator('#newsletter-message');

    await emailInput.fill('server.error@example.com');
    await submitButton.click();

    // Should show error
    await expect(messageEl).not.toHaveClass(/hidden/, { timeout: 5000 });
    const messageText = await messageEl.textContent();
    expect(messageText).toBeTruthy();
  });

  test('newsletter button re-enables after network failure', async ({ page }) => {
    await page.goto('/');
    await page.locator('footer').scrollIntoViewIfNeeded();

    await page.route('/api/newsletter', async (route) => {
      await route.abort('failed');
    });

    const emailInput = page.locator('#newsletter-email');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');

    await emailInput.fill('recovery@example.com');
    await submitButton.click();

    // Wait for error handling
    await page.waitForTimeout(3000);

    // Button should be re-enabled
    await expect(submitButton).toBeEnabled();
  });
});

test.describe('Newsletter Subscription - Accessibility', () => {
  test('newsletter email field has accessible label', async ({ page }) => {
    await page.goto('/');
    await page.locator('footer').scrollIntoViewIfNeeded();

    const emailInput = page.locator('#newsletter-email');

    // Check for label or placeholder
    const hasLabel = await page.locator('label[for="newsletter-email"]').count() > 0;
    const placeholder = await emailInput.getAttribute('placeholder');
    const ariaLabel = await emailInput.getAttribute('aria-label');

    expect(hasLabel || placeholder || ariaLabel).toBeTruthy();
  });

  test('newsletter submit button has accessible text', async ({ page }) => {
    await page.goto('/');
    await page.locator('footer').scrollIntoViewIfNeeded();

    const submitButton = page.locator('#newsletter-form button[type="submit"]');
    const text = await submitButton.textContent();
    const ariaLabel = await submitButton.getAttribute('aria-label');

    expect((text && text.trim().length > 0) || ariaLabel).toBeTruthy();
  });

  test('newsletter form is keyboard accessible', async ({ page }) => {
    await page.goto('/');

    // Tab to newsletter form
    const emailInput = page.locator('#newsletter-email');
    await emailInput.scrollIntoViewIfNeeded();
    await emailInput.focus();

    // Should be focusable
    await expect(emailInput).toBeFocused();

    // Tab to submit button
    await page.keyboard.press('Tab');
    const submitButton = page.locator('#newsletter-form button[type="submit"]');
    await expect(submitButton).toBeFocused();
  });
});

test.describe('Newsletter Subscription - Mobile Experience', () => {
  test.use({ viewport: { width: 375, height: 667 } });

  test('newsletter form is visible and usable on mobile', async ({ page }) => {
    await page.goto('/');
    await page.waitForLoadState('networkidle');

    const form = page.locator('#newsletter-form');
    await form.scrollIntoViewIfNeeded();
    await expect(form).toBeVisible();

    const emailInput = page.locator('#newsletter-email');
    await emailInput.tap();
    await emailInput.fill('mobile.newsletter@example.com');
    await expect(emailInput).toHaveValue('mobile.newsletter@example.com');
  });

  test('newsletter email input triggers email keyboard on mobile', async ({ page }) => {
    await page.goto('/');

    const emailInput = page.locator('#newsletter-email');
    const inputType = await emailInput.getAttribute('type');
    expect(inputType).toBe('email'); // This triggers email keyboard
  });

  test('newsletter form submit button is tappable on mobile', async ({ page }) => {
    await page.goto('/');

    const submitButton = page.locator('#newsletter-form button[type="submit"]');
    await submitButton.scrollIntoViewIfNeeded();
    await expect(submitButton).toBeVisible();

    // Check the button is large enough to tap (min 44x44 per WCAG)
    const box = await submitButton.boundingBox();
    expect(box).toBeTruthy();
    expect(box!.height).toBeGreaterThanOrEqual(40); // Slightly lenient
  });
});
