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

/**
 * Inline Lead Form — Homepage
 *
 * Covers:
 * - The form is mounted on the homepage between FAQ/tech-stack and the
 *   final CTA band.
 * - It exposes the compact 5-field layout (name, email, phone, project type,
 *   message) with the correct mobile keyboard hints per field. Only name,
 *   email and project type are required; phone and message are optional.
 * - Filling the required fields and submitting calls /api/contact and shows
 *   an in-place thank-you state without a full-page navigation.
 * - The submission is tagged `source: 'homepage-inline'` so leads can be
 *   segmented downstream.
 * - The backend itself accepts the new inline payload shape
 *   (server-side validation check).
 */

test.describe('Inline Lead Form (homepage)', () => {
  test('form is visible on the homepage with the compact field set and mobile keyboards', async ({ page }) => {
    await page.goto('/');

    const form = page.getByTestId('inline-lead-form');
    await form.scrollIntoViewIfNeeded();
    await expect(form).toBeVisible();

    await expect(page.locator('#inline-lead-name')).toBeVisible();
    await expect(page.locator('#inline-lead-email')).toBeVisible();
    await expect(page.locator('#inline-lead-phone')).toBeVisible();
    await expect(page.locator('#inline-lead-project-type')).toBeVisible();
    await expect(page.locator('#inline-lead-message')).toBeVisible();

    // Touch-target sanity: the submit button must be at least 48px tall.
    const submit = page.locator('#inline-lead-submit');
    const submitBox = await submit.boundingBox();
    expect(submitBox).not.toBeNull();
    expect(submitBox!.height).toBeGreaterThanOrEqual(48);

    // Correct mobile keyboard per field.
    await expect(page.locator('#inline-lead-email')).toHaveAttribute('type', 'email');
    await expect(page.locator('#inline-lead-email')).toHaveAttribute('inputmode', 'email');
    await expect(page.locator('#inline-lead-email')).toHaveAttribute('autocomplete', 'email');
    await expect(page.locator('#inline-lead-phone')).toHaveAttribute('type', 'tel');
    await expect(page.locator('#inline-lead-phone')).toHaveAttribute('inputmode', 'tel');
    await expect(page.locator('#inline-lead-phone')).toHaveAttribute('autocomplete', 'tel');

    // Phone + message are optional (no `required` attribute).
    await expect(page.locator('#inline-lead-phone')).not.toHaveAttribute('required', /.*/);
    await expect(page.locator('#inline-lead-message')).not.toHaveAttribute('required', /.*/);
  });

  test('blocks submit when required fields are empty', async ({ page }) => {
    await page.goto('/');
    const form = page.getByTestId('inline-lead-form');
    await form.scrollIntoViewIfNeeded();

    // Intercept so a real submit can't slip through if the validator fails.
    let apiCalled = false;
    await page.route('**/api/contact', async (route) => {
      apiCalled = true;
      await route.fulfill({
        status: 200,
        contentType: 'application/json',
        body: JSON.stringify({ success: true, message: 'ok' }),
      });
    });

    await page.locator('#inline-lead-submit').click();

    // The blank-field errors should surface and the network should NOT be hit.
    await expect(page.locator('#inline-lead-name-error')).toBeVisible();
    await expect(page.locator('#inline-lead-email-error')).toBeVisible();
    await expect(page.locator('#inline-lead-project-type-error')).toBeVisible();
    expect(apiCalled).toBe(false);
  });

  test('fills the required fields and submits successfully', async ({ page }) => {
    await page.goto('/');
    const form = page.getByTestId('inline-lead-form');
    await form.scrollIntoViewIfNeeded();

    // Capture the outgoing payload so we can assert source/projectType tagging.
    let captured: any = null;
    await page.route('**/api/contact', async (route) => {
      const req = route.request();
      try {
        captured = req.postDataJSON();
      } catch {
        captured = null;
      }
      await route.fulfill({
        status: 200,
        contentType: 'application/json',
        headers: { 'Access-Control-Allow-Origin': '*' },
        body: JSON.stringify({ success: true, message: 'Received.' }),
      });
    });

    await page.locator('#inline-lead-name').fill('Inline Lead Tester');
    await page.locator('#inline-lead-email').fill('inline-lead@example.com');
    await page.locator('#inline-lead-project-type').selectOption('Web App');
    await page.locator('#inline-lead-submit').click();

    // Success state should replace the form in-place, no navigation.
    await expect(page.getByTestId('inline-lead-success')).toBeVisible();
    await expect(page.getByTestId('inline-lead-success')).toContainText(
      "Thanks! We'll reply within 24 hours."
    );
    await expect(page).toHaveURL(/\/$|\/#?$/);

    // Confirm the payload is tagged correctly.
    expect(captured).toBeTruthy();
    expect(captured.source).toBe('homepage-inline');
    expect(captured.projectType).toBe('Web App');
    expect(captured.name).toBe('Inline Lead Tester');
    expect(captured.email).toBe('inline-lead@example.com');
    expect(captured.subject).toBe('web-development');
    // Message is synthesized when left blank so the backend's >=10 char rule passes.
    expect(typeof captured.message).toBe('string');
    expect(captured.message.length).toBeGreaterThanOrEqual(10);
    // Honeypot must be empty for a real user submission.
    expect(captured.website ?? '').toBe('');
  });

  test('sends the phone and a typed message through their own fields', async ({ page }) => {
    await page.goto('/');
    const form = page.getByTestId('inline-lead-form');
    await form.scrollIntoViewIfNeeded();

    let captured: any = null;
    await page.route('**/api/contact', async (route) => {
      try {
        captured = route.request().postDataJSON();
      } catch {
        captured = null;
      }
      await route.fulfill({
        status: 200,
        contentType: 'application/json',
        body: JSON.stringify({ success: true, message: 'Received.' }),
      });
    });

    await page.locator('#inline-lead-name').fill('Phone Lead');
    await page.locator('#inline-lead-email').fill('phone-lead@example.com');
    await page.locator('#inline-lead-phone').fill('+91 95614 17403');
    await page.locator('#inline-lead-project-type').selectOption('Government / GeM');
    await page.locator('#inline-lead-message').fill('We need a GeM-ready procurement portal.');
    await page.locator('#inline-lead-submit').click();

    await expect(page.getByTestId('inline-lead-success')).toBeVisible();

    expect(captured).toBeTruthy();
    // The real email and phone are sent as-is in their own fields.
    expect(captured.email).toBe('phone-lead@example.com');
    expect(captured.phone).toBe('+91 95614 17403');
    expect(captured.message).toBe('We need a GeM-ready procurement portal.');
    expect(captured.subject).toBe('government-systems');
    expect(captured.source).toBe('homepage-inline');
  });
});

// ============================================================
// Server-side: /api/contact accepts the inline lead payload
// ============================================================
test.describe('API: inline-lead payload (/api/contact)', () => {
  test('accepts a payload tagged source=homepage-inline', async ({ request }) => {
    const response = await request.post('/api/contact', {
      headers: { 'Content-Type': 'application/json' },
      data: {
        name: 'Inline API Test',
        email: 'inline-api@example.com',
        subject: 'web-development',
        message:
          'New inline lead from the homepage.\n\nProject type: Web App\nPreferred contact: inline-api@example.com',
        source: 'homepage-inline',
        projectType: 'Web App',
        website: '',
      },
    });

    // 200 success or 429 rate-limited (both acceptable in CI re-runs).
    expect([200, 429]).toContain(response.status());
    if (response.status() === 200) {
      const body = (await response.json()) as { success: boolean };
      expect(body.success).toBe(true);
    }
  });

  test('accepts the new erp-solutions and government-systems subjects', async ({ request }) => {
    for (const subject of ['erp-solutions', 'government-systems']) {
      const response = await request.post('/api/contact', {
        headers: { 'Content-Type': 'application/json' },
        data: {
          name: 'Inline API Subject Test',
          email: `inline-${subject}@example.com`,
          subject,
          message: `Inline lead for ${subject}. Project type test.`,
          source: 'homepage-inline',
          projectType: subject === 'erp-solutions' ? 'ERP / Custom Software' : 'Government / GeM',
          website: '',
        },
      });

      // Either accepted or rate-limited — both prove the subject is recognized
      // (a rejected subject would 422 instead).
      expect([200, 429]).toContain(response.status());
    }
  });

  test('still rejects payloads missing required fields', async ({ request }) => {
    const response = await request.post('/api/contact', {
      headers: { 'Content-Type': 'application/json' },
      data: {
        name: '',
        email: 'inline-missing@example.com',
        subject: 'web-development',
        message: 'A message long enough to pass validation.',
        source: 'homepage-inline',
        website: '',
      },
    });

    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('treats unknown source values as the safe default and still accepts the lead', async ({ request }) => {
    const response = await request.post('/api/contact', {
      headers: { 'Content-Type': 'application/json' },
      data: {
        name: 'Unknown Source Test',
        email: 'inline-unknown@example.com',
        subject: 'other',
        message: 'Inline lead from an unrecognised source string.',
        source: 'totally-made-up-source',
        projectType: 'Other',
        website: '',
      },
    });

    expect([200, 429]).toContain(response.status());
  });
});
