import { expect, test, type Page } from '@playwright/test';
import { expectNoA11yViolations } from './support/axe';
import { signIn, signInSupport } from './support/cms';

/**
 * História 23 — Painel de suporte (P3.S1/ADR-033).
 *
 * Jornada: o administrador (perfil máximo, sem a identidade da equipe) **não vê** o grupo
 * `Suporte` na navegação e recebe **404** ao digitar a URL; a equipe de suporte vê o item, abre a
 * visão geral e a tela passa no axe (A/AA). Dados da semente demo: nenhum spec depende deste spec.
 */
test.describe('CMS — Painel de suporte', () => {
  test('fora da equipe o grupo é invisível e a área responde 404', async ({ page }) => {
    await signIn(page);

    // Perfil máximo do cliente: o grupo reservado não aparece no menu (ADR-033).
    await expect(page.getByRole('link', { name: 'Painel de suporte' })).toHaveCount(0);
    await expect(page.getByText('Suporte', { exact: true })).toHaveCount(0);

    // URL digitada: 404 (não 403) para não revelar a existência da área.
    for (const path of ['/suporte', '/suporte/modulos', '/suporte/auditoria', '/suporte/manutencao']) {
      const response = await page.goto(path);
      expect(response?.status(), path).toBe(404);
    }
  });

  test('a equipe de suporte vê o item e a visão geral', async ({ page }) => {
    await signInSupport(page);

    const link = page.getByRole('link', { name: 'Painel de suporte' });
    await expect(link).toBeVisible();
    await expectNoA11yViolations(page);

    await link.click();

    await expect(page).toHaveURL(/\/suporte$/);
    await expect(page.getByRole('heading', { name: 'Painel de suporte', level: 1 })).toBeVisible();
    await expect(page.getByRole('heading', { name: 'Módulos' })).toBeVisible();
    await expect(page.getByText('Módulos descobertos')).toBeVisible();
    await expect(page.getByRole('heading', { name: 'Regras desta área' })).toBeVisible();

    await expectNoA11yViolations(page);
  });
});

/**
 * Ativação/desativação em runtime (P3.S2/ADR-034): a equipe desativa um módulo não essencial,
 * confere o **404 imediato** no portal (sem optimize/reload), reativa e o portal volta a 200.
 * O estado global é restaurado no `finally` — nenhuma outra spec depende da janela intermediária.
 */
const BLUEPRINT = 'Blueprint';

/** Portal público: a base do `BASE_URL` (o painel vive em `cms.<base>`). */
function portal(path: string): string {
  return new URL(path, process.env.BASE_URL ?? 'http://localhost:50700').toString();
}

async function toggle(page: Page, label: string, reason: string): Promise<void> {
  const row = page.locator(`tr[data-module="${BLUEPRINT}"]`);

  await row.getByRole('button', { name: label, exact: true }).click();
  await row.getByLabel('Motivo').fill(reason);

  await Promise.all([
    page.waitForURL(/\/suporte\/modulos$/),
    row.locator('form').getByRole('button', { name: label, exact: true }).click(),
  ]);
}

/** Cleanup determinístico: se uma execução anterior caiu no meio, reativa pelo próprio painel. */
async function ensureBlueprintActive(page: Page): Promise<void> {
  await page.goto('/suporte/modulos');

  const row = page.locator(`tr[data-module="${BLUEPRINT}"]`);
  await expect(row).toHaveCount(1);

  if ((await row.getByRole('button', { name: 'Ativar', exact: true }).count()) > 0) {
    await toggle(page, 'Ativar', 'Restauração após execução interrompida (e2e)');
  }
}

test('a equipe desativa e reativa um módulo com efeito imediato', async ({ page }) => {
  await signInSupport(page);
  // Normaliza o modo de manutenção (estado global): uma execução interrompida do caso de
  // manutenção não pode transformar o 404/200 do portal em 503.
  await disableMaintenance(page);
  await ensureBlueprintActive(page);

  const row = page.locator(`tr[data-module="${BLUEPRINT}"]`);
  await expect(row).toHaveCount(1);
  await expect(page.getByRole('heading', { name: 'Módulos do sistema', level: 1 })).toBeVisible();
  await expectNoA11yViolations(page);

  // Essenciais e o próprio grupo `Suporte` nunca oferecem toggle na UI (recusa também no server).
  for (const [name, badge] of [
    ['Acesso', 'Essencial'],
    ['Configuracoes', 'Essencial'],
    ['Painel', 'Protegido'],
  ] as const) {
    const protectedRow = page.locator(`tr[data-module="${name}"]`);
    await expect(protectedRow).toHaveCount(1);
    await expect(protectedRow.getByText(badge, { exact: true })).toBeVisible();
    await expect(protectedRow.getByRole('button', { name: 'Desativar', exact: true })).toHaveCount(0);
    await expect(protectedRow.getByRole('button', { name: 'Ativar', exact: true })).toHaveCount(0);
  }

  try {
    await toggle(page, 'Desativar', 'Janela de manutenção (e2e)');

    await expect(page.getByRole('alert')).toContainText('Módulo desativado.');
    await expect(page.locator(`tr[data-module="${BLUEPRINT}"]`).getByText('Inativo')).toBeVisible();

    // O request seguinte já responde 404 — sem optimize nem reload do FPM.
    const deactivated = await page.goto(portal('/blueprint'));
    expect(deactivated?.status()).toBe(404);

    await page.goto('/suporte/modulos');
    await toggle(page, 'Ativar', 'Fim da janela (e2e)');

    await expect(page.getByRole('alert')).toContainText('Módulo ativado.');

    const reactivated = await page.goto(portal('/blueprint'));
    expect(reactivated?.status()).toBe(200);
  } finally {
    await ensureBlueprintActive(page);
  }
});

/**
 * Diagnóstico somente leitura (P3.S3): a equipe abre a tela pelo link da visão geral, vê os
 * cartões de estado (com o `scheduler` explicitamente indisponível — não há heartbeat nativo) e a
 * página passa no axe. Nada é mutado: nenhuma limpeza é necessária.
 */
test('a equipe abre o diagnóstico do sistema e a tela passa no axe', async ({ page }) => {
  await signInSupport(page);

  await page.goto('/suporte');

  const link = page.getByRole('link', { name: 'Diagnóstico', exact: true });
  await expect(link).toBeVisible();
  await link.click();

  await expect(page).toHaveURL(/\/suporte\/diagnostico$/);
  await expect(page.getByRole('heading', { name: 'Diagnóstico do sistema', level: 1 })).toBeVisible();
  await expect(page.getByRole('heading', { name: 'Plataforma' })).toBeVisible();

  // Estado/valor real, não o rótulo: a versão vem de `VERSION` e o servidor é o PostgreSQL.
  const version = page.locator('[data-check="version"]');
  await expect(version).toHaveAttribute('data-check-status', 'ok');
  await expect(version.locator('[data-check-value]')).toHaveText(/^\d+\.\d+\.\d+/);

  const database = page.locator('[data-check="database"]');
  await expect(database).toHaveAttribute('data-check-status', 'ok');
  await expect(database.locator('[data-check-value]')).toHaveText(/^PostgreSQL \d+/);

  // `scheduler` é explicitamente indisponível (o Laravel não expõe heartbeat de `schedule:run`).
  const scheduler = page.locator('[data-check="scheduler"]');
  await expect(scheduler).toHaveAttribute('data-check-status', 'unavailable');
  await expect(scheduler.locator('[data-check-value]')).toContainText('scheduler');

  await expectNoA11yViolations(page);
});

/**
 * Leitor da trilha (P3.S4): a equipe abre a lista pelo link da visão geral, filtra por evento,
 * confere que a seleção é preservada na URL/paginação e abre o detalhe de um evento — que mostra
 * o hash de integridade e passa no axe. A trilha é **append-only**: o spec não cria dado mutável,
 * então não há limpeza (os eventos de leitura são a própria evidência).
 */
test('a equipe filtra a trilha e abre o detalhe de um evento', async ({ page }) => {
  await signInSupport(page);

  await page.goto('/suporte');

  const link = page.getByRole('link', { name: 'Auditoria', exact: true });
  await expect(link).toBeVisible();
  await link.click();

  await expect(page).toHaveURL(/\/suporte\/auditoria$/);
  await expect(page.getByRole('heading', { name: 'Trilha de auditoria', level: 1 })).toBeVisible();
  await expect(page.getByRole('table', { name: 'Eventos da trilha de auditoria' })).toBeVisible();

  await expectNoA11yViolations(page);

  // A visita acima já gravou um evento de acesso (`painel.view`); o filtro o encontra.
  await page.getByLabel('Evento').fill('painel.view');
  await Promise.all([
    page.waitForURL(/event=painel\.view/),
    page.getByRole('button', { name: 'Filtrar' }).click(),
  ]);

  await expect(page.getByLabel('Evento')).toHaveValue('painel.view');

  const rows = page.locator('tr[data-audit-id]');
  await expect(rows.first()).toBeVisible();
  await expect(rows.first()).toHaveAttribute('data-event', 'painel.view');

  await expectNoA11yViolations(page);

  await Promise.all([
    page.waitForURL(/\/suporte\/auditoria\/[0-9a-f-]{36}$/),
    page.getByRole('link', { name: 'Ver detalhe', exact: true }).first().click(),
  ]);

  await expect(page.getByRole('heading', { name: 'Detalhe do evento', level: 1 })).toBeVisible();
  await expect(page.getByText('Hash de integridade')).toBeVisible();
  await expect(page.getByText('Evento registrado')).toBeVisible();

  await expectNoA11yViolations(page);
});

test('a equipe liga a manutenção, portal/API respondem 503 e desligar restaura', async ({ page, request }) => {
  await signInSupport(page);
  // Normaliza estado de uma execução anterior antes de abrir a janela e fotografa a configuração
  // vigente (mensagem/retorno/allow_cms) para restaurá-la no `finally` — nada de resíduo de e2e.
  await disableMaintenance(page);
  const original = await readMaintenance(page);

  const portalBase = process.env.BASE_URL ?? 'http://localhost:50700';
  const apiBase = (process.env.API_BASE_URL ?? new URL(portalBase).origin.replace('://', '://api.')).replace(/\/$/, '');

  try {
    await page.goto('/suporte/manutencao');
    await expect(page.getByRole('heading', { name: 'Modo de manutenção', level: 1 })).toBeVisible();
    await expectNoA11yViolations(page);

    await page.getByLabel('Ativar modo de manutenção', { exact: true }).check();
    await page.getByLabel('Mensagem exibida', { exact: true }).fill('Manutenção programada (e2e)');
    await page.getByLabel('Retorno em segundos', { exact: true }).fill('120');
    await page.getByLabel('Manter o painel acessível', { exact: true }).check();
    await page.getByLabel('Confirmo a alteração do modo de manutenção', { exact: true }).check();

    await Promise.all([
      page.waitForURL(/\/suporte\/manutencao$/),
      page.getByRole('button', { name: 'Salvar', exact: true }).click(),
    ]);

    await expect(page.getByRole('alert')).toContainText('Modo de manutenção atualizado.');
    await expect(page.getByText('Em manutenção', { exact: true })).toBeVisible();

    // O painel continua acessível para a equipe (`allow_cms`).
    const cms = await page.goto('/suporte');
    expect(cms?.status()).toBe(200);

    // Portal: 503 HTML acessível, Retry-After e noindex.
    const portalResponse = await page.goto(portal('/blueprint'));
    expect(portalResponse?.status()).toBe(503);
    expect(portalResponse?.headers()['retry-after']).toBe('120');
    expect(portalResponse?.headers()['x-robots-tag']).toContain('noindex');

    await expect(page.getByRole('heading', { name: 'Sistema em manutenção', level: 1 })).toBeVisible();
    await expect(page.getByText('Manutenção programada (e2e)')).toBeVisible();
    await expectNoA11yViolations(page);

    // API: 503 RFC 7807, Retry-After e sem detalhe técnico.
    const api = await request.get(`${apiBase}/`, { headers: { Accept: 'application/json' } });
    expect(api.status()).toBe(503);
    expect(api.headers()['content-type']).toContain('application/problem+json');
    expect(api.headers()['retry-after']).toBe('120');
    expect(api.headers()['x-request-id']).toBeTruthy();

    const problem = await api.json();
    expect(problem.status).toBe(503);
    expect(problem.retry_after).toBe(120);
    expect(JSON.stringify(problem)).not.toContain('Exception');
  } finally {
    // Restauração determinística mesmo em falha: configuração original, portal de volta a 200.
    await saveMaintenance(page, { ...original, enabled: false });
  }

  const restored = await page.goto(portal('/blueprint'));
  expect(restored?.status()).toBe(200);
});

/** Configuração corrente do formulário de manutenção (para normalizar e restaurar). */
interface MaintenanceForm {
  enabled: boolean;
  message: string;
  retry: string;
  allowCms: boolean;
}

async function readMaintenance(page: Page): Promise<MaintenanceForm> {
  await page.goto('/suporte/manutencao');

  return {
    enabled: await page.getByLabel('Ativar modo de manutenção', { exact: true }).isChecked(),
    message: await page.getByLabel('Mensagem exibida', { exact: true }).inputValue(),
    retry: await page.getByLabel('Retorno em segundos', { exact: true }).inputValue(),
    allowCms: await page.getByLabel('Manter o painel acessível', { exact: true }).isChecked(),
  };
}

/** Grava o formulário inteiro com a confirmação explícita exigida pelo servidor. */
async function saveMaintenance(page: Page, state: MaintenanceForm): Promise<void> {
  await page.goto('/suporte/manutencao');

  const enabled = page.getByLabel('Ativar modo de manutenção', { exact: true });
  const allowCms = page.getByLabel('Manter o painel acessível', { exact: true });

  if (state.enabled) {
    await enabled.check();
  } else {
    await enabled.uncheck();
  }

  await page.getByLabel('Mensagem exibida', { exact: true }).fill(state.message);
  await page.getByLabel('Retorno em segundos', { exact: true }).fill(state.retry);

  if (state.allowCms) {
    await allowCms.check();
  } else {
    await allowCms.uncheck();
  }

  await page.getByLabel('Confirmo a alteração do modo de manutenção', { exact: true }).check();

  await Promise.all([
    page.waitForURL(/\/suporte\/manutencao$/),
    page.getByRole('button', { name: 'Salvar', exact: true }).click(),
  ]);

  await expect(page.getByRole('alert')).toContainText('Modo de manutenção atualizado.');
}

/** Garante o modo de manutenção desligado (idempotente para execuções interrompidas). */
async function disableMaintenance(page: Page): Promise<void> {
  const current = await readMaintenance(page);

  if (current.enabled) {
    await saveMaintenance(page, { ...current, enabled: false });
  }
}


/**
 * Contato do fornecedor e versão (P3.S6): a equipe abre a tela pela visão geral, vê o estado
 * vazio explicativo (nunca página em branco) e a versão do pacote; preenche os canais em
 * Configurações e os confere na tela — site/WhatsApp abrem em nova aba com `rel=noopener`,
 * telefone/e-mail como links de navegação, endereço em texto e nenhum iframe/mapa de terceiro.
 * Os dados da seção `support` são normalizados para vazio antes e restaurados no `finally`.
 */
const SUPPORT_CONTACT = {
  company: 'Fornecedor E2E Ltda.',
  site: 'https://fornecedor.example.com.br',
  email: 'contato@fornecedor.example.com.br',
  phone: '+55 11 4000-0000',
  whatsapp: '+55 11 99999-0000',
  address: 'Rua E2E, 100\nCentro',
  hours: '9h às 18h',
} as const;

async function clearSupportContact(page: Page): Promise<void> {
  await page.goto('/configuracoes/support');

  for (const label of [
    'Empresa fornecedora',
    'Site do fornecedor',
    'E-mail de contato',
    'Telefone de contato',
    'WhatsApp',
    'Endereço do fornecedor',
    'Horário de atendimento',
  ]) {
    await page.getByLabel(label, { exact: true }).fill('');
  }

  await page.getByRole('button', { name: 'Salvar', exact: true }).click();
  await expect(page.getByRole('alert')).toContainText('Configurações salvas.');
}

test('a equipe consulta o contato do fornecedor e a versão', async ({ page }) => {
  await signInSupport(page);
  // Estado inicial determinístico, mesmo após uma execução interrompida.
  await clearSupportContact(page);

  try {
    await page.goto('/suporte');

    const link = page.getByRole('link', { name: 'Contato do fornecedor', exact: true });
    await expect(link).toBeVisible();
    await link.click();

    await expect(page).toHaveURL(/\/suporte\/contato$/);
    await expect(page.getByRole('heading', { name: 'Contato do fornecedor', level: 1 })).toBeVisible();
    await expect(page.locator('[data-contact-state="empty"]')).toBeVisible();
    await expect(page.getByText('Nenhum fornecedor configurado')).toBeVisible();
    await expect(page.locator('[data-version]')).not.toBeEmpty();
    await expect(page.getByRole('link', { name: 'Configurar contato do fornecedor' })).toBeVisible();
    await expect(page.locator('iframe')).toHaveCount(0);
    await expectNoA11yViolations(page);

    await page.goto('/configuracoes/support');
    await page.getByLabel('Empresa fornecedora', { exact: true }).fill(SUPPORT_CONTACT.company);
    await page.getByLabel('Site do fornecedor', { exact: true }).fill(SUPPORT_CONTACT.site);
    await page.getByLabel('E-mail de contato', { exact: true }).fill(SUPPORT_CONTACT.email);
    await page.getByLabel('Telefone de contato', { exact: true }).fill(SUPPORT_CONTACT.phone);
    await page.getByLabel('WhatsApp', { exact: true }).fill(SUPPORT_CONTACT.whatsapp);
    await page.getByLabel('Endereço do fornecedor', { exact: true }).fill(SUPPORT_CONTACT.address);
    await page.getByLabel('Horário de atendimento', { exact: true }).fill(SUPPORT_CONTACT.hours);

    await page.getByRole('button', { name: 'Salvar', exact: true }).click();
    await expect(page.getByRole('alert')).toContainText('Configurações salvas.');

    await page.goto('/suporte/contato');
    await expect(page.locator('[data-contact-state="configured"]')).toBeVisible();
    await expect(page.getByText(SUPPORT_CONTACT.company)).toBeVisible();
    await expect(page.getByText('Rua E2E, 100')).toBeVisible();
    await expect(page.getByText(SUPPORT_CONTACT.hours)).toBeVisible();

    const site = page.getByRole('link', { name: 'fornecedor.example.com.br', exact: true });
    await expect(site).toHaveAttribute('href', SUPPORT_CONTACT.site);
    await expect(site).toHaveAttribute('target', '_blank');
    await expect(site).toHaveAttribute('rel', 'noopener');

    await expect(page.getByRole('link', { name: SUPPORT_CONTACT.email, exact: true }))
      .toHaveAttribute('href', `mailto:${SUPPORT_CONTACT.email}`);
    await expect(page.getByRole('link', { name: SUPPORT_CONTACT.phone, exact: true }))
      .toHaveAttribute('href', 'tel:+551140000000');

    const whatsapp = page.getByRole('link', { name: SUPPORT_CONTACT.whatsapp, exact: true });
    await expect(whatsapp).toHaveAttribute('href', 'https://wa.me/5511999990000');
    await expect(whatsapp).toHaveAttribute('target', '_blank');
    await expect(whatsapp).toHaveAttribute('rel', 'noopener');

    await expect(page.locator('iframe')).toHaveCount(0);
    await expectNoA11yViolations(page);
  } finally {
    await clearSupportContact(page);
  }

  await page.goto('/suporte/contato');
  await expect(page.locator('[data-contact-state="empty"]')).toBeVisible();
});
