import { expect, test } from '@playwright/test';
import { expectNoA11yViolations } from './support/axe';

/**
 * História 12 — Dados abertos (ADR-018).
 *
 * Prova que o catálogo público lista os conjuntos **publicados**, o detalhe expõe os downloads
 * CSV/JSON/XML e que as duas telas passam no axe (ADR-025). Pré-condição: `php artisan db:seed`.
 */
test.describe('Dados Abertos — catálogo e downloads', () => {
  test('o catálogo lista datasets publicados e passa no axe', async ({ page }) => {
    await page.goto('/dados-abertos');

    await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
    await expect(page.locator('main a[href*="/dados-abertos/"]').first()).toBeVisible();

    await expectNoA11yViolations(page);
  });

  test('o detalhe expõe os downloads CSV/JSON/XML e passa no axe', async ({ page }) => {
    await page.goto('/dados-abertos');
    await page.locator('main a[href*="/dados-abertos/"]').first().click();

    await expect(page.getByRole('heading', { level: 2, name: 'Downloads' })).toBeVisible();

    for (const format of ['CSV', 'JSON', 'XML']) {
      await expect(page.getByRole('link', { name: format, exact: true })).toBeVisible();
    }

    await expectNoA11yViolations(page);
  });

  test('a API v1 responde CORS para o navegador', async ({ page }) => {
    // O consumidor real é cross-origin (dashboard de terceiro). A página do portal não serve:
    // a CSP dela (`connect-src 'self'`) bloqueia a chamada — de propósito. Servimos um documento
    // externo via `route` (origem distinta, sem CSP) e chamamos a API de lá. `*.localhost`
    // mantém o consumidor no mesmo address space (PNA bloqueia loopback a partir de origem pública).
    const portal = new URL(process.env.BASE_URL ?? 'http://localhost:8080').origin;
    const api = process.env.API_BASE_URL ?? portal.replace('://', '://api.');

    await page.route('http://consumidor.localhost/**', (route) =>
      route.fulfill({ contentType: 'text/html; charset=utf-8', body: '<!doctype html><title>consumidor</title>' }),
    );
    await page.goto('http://consumidor.localhost/');

    type Probe = { status?: number; type?: string; checksum?: string | null; error?: string };
    const probe = (headers: Record<string, string>) =>
      page.evaluate<Probe, { url: string; headers: Record<string, string> }>(
        async ({ url, headers }) => {
          try {
            const response = await fetch(url, { headers });
            await response.json();

            return {
              status: response.status,
              type: response.type,
              checksum: response.headers.get('x-checksum-sha256'),
            };
          } catch (error) {
            return { error: String(error) };
          }
        },
        { url: `${api}/v1/datasets`, headers },
      );

    // GET simples: sem ACAO o `fetch` rejeitaria; `type: 'cors'` prova que a resposta foi liberada.
    const simple = await probe({ Accept: 'application/json' });
    expect(simple.error).toBeUndefined();
    expect(simple.status).toBe(200);
    expect(simple.type).toBe('cors');
    // `Access-Control-Expose-Headers` libera o checksum para o JS do consumidor.
    expect(simple.checksum).toMatch(/^[0-9a-f]{64}$/);

    // Cabeçalho não-simples (`Authorization`) dispara preflight `OPTIONS`; a API responde 204
    // com `Access-Control-Allow-Headers` e o GET seguinte completa.
    const preflight = await probe({ Accept: 'application/json', Authorization: 'Bearer teste' });
    expect(preflight.error).toBeUndefined();
    expect(preflight.status).toBe(200);
    expect(preflight.type).toBe('cors');
  });

  test('o download serve o CSV com checksum e ETag', async ({ page, request }) => {
    await page.goto('/dados-abertos');
    await page.locator('main a[href*="/dados-abertos/"]').first().click();

    const href = await page.getByRole('link', { name: 'CSV', exact: true }).getAttribute('href');
    expect(href).toBeTruthy();

    const response = await request.get(href as string);
    expect(response.status()).toBe(200);
    expect(response.headers()['content-type']).toContain('text/csv');
    expect(response.headers()['x-checksum-sha256']).toBeTruthy();
    expect(response.headers()['etag']).toBeTruthy();
  });
});
