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

/**
 * POC Production Test Suite
 * Codifies all automated tests from the POC Testing Phase (P0–P4, P7).
 *
 * Run: npx playwright test --config=playwright.poc.config.ts e2e/poc-production.spec.ts
 */

const BASE = process.env.SMOKE_BASE_URL || 'https://llmhosts.com';

// ---------------------------------------------------------------------------
// P0 — Infrastructure Smoke
// ---------------------------------------------------------------------------
test.describe('P0: Infrastructure Smoke', () => {
  const publicEndpoints = [
    { path: '/', expected: 200 },
    { path: '/pricing', expected: 200 },
    { path: '/contact', expected: 200 },
    { path: '/legal/terms', expected: 200 },
    { path: '/legal/privacy', expected: 200 },
    { path: '/auth/login', expected: 200 },
    { path: '/auth/register', expected: 200 },
  ];

  for (const { path, expected } of publicEndpoints) {
    test(`GET ${path} → ${expected}`, async ({ request }) => {
      const res = await request.get(`${BASE}${path}`);
      expect(res.status()).toBe(expected);
    });
  }

  test('GET /health → 200 (API)', async ({ request }) => {
    const res = await request.get(`${BASE}/health`);
    expect(res.status()).toBe(200);
    const body = await res.json();
    expect(body.status).toBe('ok');
  });

  test('GET /docs → 200 (Swagger UI)', async ({ request }) => {
    const res = await request.get(`${BASE}/docs`);
    expect(res.status()).toBe(200);
  });

  test('GET /openapi.json → valid OpenAPI spec', async ({ request }) => {
    const res = await request.get(`${BASE}/openapi.json`);
    expect(res.status()).toBe(200);
    const spec = await res.json();
    expect(spec.openapi).toMatch(/^3\./);
  });

  test('GET /v1/models → 200', async ({ request }) => {
    const res = await request.get(`${BASE}/v1/models`);
    expect(res.status()).toBe(200);
  });

  test('GET /dashboard → redirect to login', async ({ request }) => {
    const res = await request.get(`${BASE}/dashboard`, { maxRedirects: 0 });
    expect([301, 302, 307, 308]).toContain(res.status());
  });
});

// ---------------------------------------------------------------------------
// P1 — Auth & Security
// ---------------------------------------------------------------------------
test.describe('P1: Auth & Security', () => {
  const protectedRoutes = [
    '/dashboard',
    '/dashboard/settings',
    '/dashboard/api-keys',
    '/dashboard/team',
    '/dashboard/tunnel',
    '/dashboard/lan-nodes',
    '/dashboard/topology',
    '/dashboard/cost-analytics',
    '/dashboard/security',
    '/dashboard/cache',
    '/dashboard/router',
  ];

  for (const route of protectedRoutes) {
    test(`${route} redirects unauthenticated users`, async ({ request }) => {
      const res = await request.get(`${BASE}${route}`, { maxRedirects: 0 });
      expect([301, 302, 307, 308]).toContain(res.status());
      const location = res.headers()['location'] || '';
      expect(location).toContain('/auth/login');
    });
  }

  test('security headers present on frontend pages', async ({ request }) => {
    const res = await request.get(`${BASE}/`);
    const h = res.headers();
    expect(h['x-content-type-options']).toBe('nosniff');
    expect(h['x-frame-options']).toMatch(/DENY|SAMEORIGIN/i);
    expect(h['referrer-policy']).toBe('strict-origin-when-cross-origin');
    expect(h['strict-transport-security']).toMatch(/max-age=\d+/);
    expect(h['content-security-policy']).toBeTruthy();
    expect(h['permissions-policy']).toBeTruthy();
  });

  test('security headers present on API', async ({ request }) => {
    const res = await request.get(`${BASE}/health`);
    const h = res.headers();
    expect(h['x-content-type-options']).toBe('nosniff');
    expect(h['x-frame-options']).toMatch(/DENY|SAMEORIGIN/i);
    expect(h['strict-transport-security']).toMatch(/max-age=\d+/);
  });

  test('no server fingerprinting headers', async ({ request }) => {
    const res = await request.get(`${BASE}/`);
    const h = res.headers();
    expect(h['x-powered-by'] || '').toBe('');
    expect(h['server'] || '').not.toMatch(/nginx|apache|express|uvicorn/i);
  });

  test('CSRF protection on login', async ({ request }) => {
    const res = await request.post(`${BASE}/api/auth/callback/credentials`, {
      headers: { 'Content-Type': 'application/json' },
      data: { email: 'test@test.com', password: 'test' },
      maxRedirects: 0,
    });
    // Should not succeed without CSRF token — redirect or error
    expect(res.status()).toBeGreaterThanOrEqual(302);
  });
});

// ---------------------------------------------------------------------------
// P2 — Dashboard Routes
// ---------------------------------------------------------------------------
test.describe('P2: Dashboard Route Protection', () => {
  const routes = [
    '/dashboard',
    '/dashboard/settings',
    '/dashboard/api-keys',
    '/dashboard/team',
    '/dashboard/tunnel',
    '/dashboard/lan-nodes',
    '/dashboard/topology',
    '/dashboard/cost-analytics',
    '/dashboard/security',
    '/dashboard/cache',
    '/dashboard/router',
  ];

  for (const route of routes) {
    test(`${route} preserves callback URL on redirect`, async ({ request }) => {
      const res = await request.get(`${BASE}${route}`, { maxRedirects: 0 });
      const location = res.headers()['location'] || '';
      expect(location).toContain('callbackUrl');
    });
  }
});

// ---------------------------------------------------------------------------
// P3 — API Proxy
// ---------------------------------------------------------------------------
test.describe('P3: API Proxy', () => {
  test('GET /v1/models returns model list', async ({ request }) => {
    const res = await request.get(`${BASE}/v1/models`);
    expect(res.status()).toBe(200);
    const body = await res.json();
    expect(body).toHaveProperty('data');
    expect(Array.isArray(body.data)).toBe(true);
  });

  test('POST /v1/chat/completions rejects malformed JSON', async ({ request }) => {
    const res = await request.post(`${BASE}/v1/chat/completions`, {
      headers: { 'Content-Type': 'application/json' },
      data: { invalid: true },
    });
    expect(res.status()).toBe(422);
  });

  test('X-Request-ID header present on API responses', async ({ request }) => {
    const res = await request.get(`${BASE}/health`);
    expect(res.headers()['x-request-id']).toBeTruthy();
  });

  test('OpenAPI spec is valid', async ({ request }) => {
    const res = await request.get(`${BASE}/openapi.json`);
    const spec = await res.json();
    expect(spec.info).toBeTruthy();
    expect(spec.paths).toBeTruthy();
    expect(Object.keys(spec.paths).length).toBeGreaterThan(0);
  });
});

// ---------------------------------------------------------------------------
// P4 — SEO & Marketing
// ---------------------------------------------------------------------------
test.describe('P4: SEO', () => {
  test('robots.txt is accessible', async ({ request }) => {
    const res = await request.get(`${BASE}/robots.txt`);
    expect(res.status()).toBe(200);
    const text = await res.text();
    expect(text).toContain('Sitemap');
  });

  test('sitemap.xml is accessible', async ({ request }) => {
    const res = await request.get(`${BASE}/sitemap.xml`);
    expect(res.status()).toBe(200);
    const text = await res.text();
    expect(text).toContain('<urlset');
  });

  test('llms.txt is accessible', async ({ request }) => {
    const res = await request.get(`${BASE}/llms.txt`);
    expect(res.status()).toBe(200);
  });

  const pagesWithMeta = [
    { path: '/', name: 'Landing' },
    { path: '/pricing', name: 'Pricing' },
    { path: '/contact', name: 'Contact' },
  ];

  for (const { path, name } of pagesWithMeta) {
    test(`${name} has OG tags`, async ({ page }) => {
      await page.goto(`${BASE}${path}`, { waitUntil: 'domcontentloaded' });
      const ogTitle = await page.locator('meta[property="og:title"]').getAttribute('content');
      const ogDesc = await page.locator('meta[property="og:description"]').getAttribute('content');
      expect(ogTitle, `og:title on ${path}`).toBeTruthy();
      expect(ogDesc, `og:description on ${path}`).toBeTruthy();
    });

    test(`${name} has JSON-LD`, async ({ page }) => {
      await page.goto(`${BASE}${path}`, { waitUntil: 'domcontentloaded' });
      const scripts = await page.locator('script[type="application/ld+json"]').count();
      expect(scripts, `JSON-LD blocks on ${path}`).toBeGreaterThan(0);
    });
  }

  const pagesWithCanonical = [
    { path: '/', expected: 'https://llmhosts.com' },
    { path: '/pricing', expected: 'https://llmhosts.com/pricing' },
    { path: '/contact', expected: 'https://llmhosts.com/contact' },
    { path: '/legal/terms', expected: 'https://llmhosts.com/legal/terms' },
    { path: '/legal/privacy', expected: 'https://llmhosts.com/legal/privacy' },
  ];

  for (const { path, expected } of pagesWithCanonical) {
    test(`${path} has canonical URL`, async ({ page }) => {
      await page.goto(`${BASE}${path}`, { waitUntil: 'domcontentloaded' });
      const canonical = await page.locator('link[rel="canonical"]').getAttribute('href');
      expect(canonical).toBe(expected);
    });
  }

  test('auth pages have noindex', async ({ page }) => {
    await page.goto(`${BASE}/auth/login`, { waitUntil: 'domcontentloaded' });
    const robotsMeta = await page.locator('meta[name="robots"]').getAttribute('content');
    expect(robotsMeta).toContain('noindex');
  });
});

// ---------------------------------------------------------------------------
// P7 — Accessibility
// ---------------------------------------------------------------------------
test.describe('P7: Accessibility', () => {
  test('contact form fields have associated labels', async ({ page }) => {
    await page.goto(`${BASE}/contact`, { waitUntil: 'domcontentloaded' });

    const nameInput = page.locator('#contact-name');
    const emailInput = page.locator('#contact-email');
    const subjectSelect = page.locator('#contact-subject');
    const messageTextarea = page.locator('#contact-message');

    await expect(nameInput).toBeVisible();
    await expect(emailInput).toBeVisible();
    await expect(subjectSelect).toBeVisible();
    await expect(messageTextarea).toBeVisible();

    // Verify labels point to the correct inputs
    const nameLabel = page.locator('label[for="contact-name"]');
    const emailLabel = page.locator('label[for="contact-email"]');
    await expect(nameLabel).toBeVisible();
    await expect(emailLabel).toBeVisible();
  });

  test('no text-gray-600 on dark background (WCAG AA)', async ({ page }) => {
    await page.goto(`${BASE}/`, { waitUntil: 'domcontentloaded' });
    const html = await page.content();
    // text-gray-600 on #080809 background fails WCAG AA — we replaced with text-gray-500
    expect(html).not.toContain('text-gray-600');
  });

  test('navigation has proper ARIA landmark', async ({ page }) => {
    await page.goto(`${BASE}/`, { waitUntil: 'domcontentloaded' });
    const nav = page.locator('nav');
    await expect(nav.first()).toBeVisible();
  });

  test('images have alt text', async ({ page }) => {
    await page.goto(`${BASE}/`, { waitUntil: 'domcontentloaded' });
    const imgsWithoutAlt = await page.locator('img:not([alt])').count();
    // Decorative images should have alt="" (empty), not be missing alt entirely
    expect(imgsWithoutAlt).toBe(0);
  });

  test('page has proper heading hierarchy', async ({ page }) => {
    await page.goto(`${BASE}/`, { waitUntil: 'domcontentloaded' });
    const h1Count = await page.locator('h1').count();
    expect(h1Count).toBeGreaterThanOrEqual(1);
  });
});
