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

/**
 * Helpers do editor da home (P5.S2.1/S2.2 — emenda ADR-016).
 *
 * O editor é um único `PUT /cms/home`: mover/ocultar/remover/salvar são submits do mesmo formulário
 * (funcionam sem JS e por teclado). Os helpers abaixo acionam a **UI real** — nunca um atalho de
 * banco — e são compartilhados pelas histórias 26 (publicação) e 31 (composição/reordenação).
 */

/** Documento AST mínimo que o renderizador do portal publica como um parágrafo. */
export function textDocument(text: string): string {
  return JSON.stringify({
    type: 'doc',
    content: [{ type: 'paragraph', content: [{ type: 'text', text }] }],
  });
}

/** Remove todas as seções do rascunho pela própria UI (submissão normal + modal nativo). */
export async function clearDraftSections(page: Page): Promise<void> {
  const triggers = page.locator('button[popovertarget$="-remove"]');

  // `BlocksSchema::MAX_SECTIONS` é 40: o laço precisa alcançar a 40ª remoção antes de desistir.
  for (let guard = 0; guard <= 40; guard += 1) {
    if ((await triggers.count()) === 0) {
      return;
    }

    await triggers.first().click();

    await Promise.all([
      page.waitForURL(/\/home$/),
      page.getByRole('button', { name: 'Confirmar remoção' }).click(),
    ]);
  }

  throw new Error('O rascunho da home não ficou vazio depois de remover as 40 seções possíveis.');
}

/** Abre a tela com uma seção **nova** (não persistida) do tipo informado. */
export async function addSection(page: Page, type: string): Promise<void> {
  await page.goto(`/home?novo=${type}`);
  await expect(page.getByRole('region', { name: 'Nova seção (ainda não salva)' })).toBeVisible();
}

/** Preenche um campo traduzível de um grupo (`Título`, `Conteúdo`) no diálogo aberto. */
export async function fillTranslatedField(
  page: Page,
  group: string,
  locale: string,
  value: string,
): Promise<void> {
  const dialog = page.getByRole('dialog');

  await expect(dialog).toBeVisible();
  await dialog.getByRole('group', { name: group }).getByLabel(locale).fill(value);
}

/** Abre o `<dialog>` nativo da seção (pending ou salva) pelo gatilho real. */
export async function openSectionDialog(page: Page, region: string): Promise<void> {
  await page
    .getByRole('region', { name: region })
    .getByRole('button', { name: 'Editar seção' })
    .click();

  await expect(page.getByRole('dialog')).toBeVisible();
}

/** Fecha o diálogo pelo botão de concluir (garante que o corpo rolou até ele). */
export async function closeSectionDialog(page: Page): Promise<void> {
  const close = page.getByRole('dialog').getByRole('button', { name: 'Concluir edição' });

  await close.scrollIntoViewIfNeeded();
  await close.click();
  await expect(page.getByRole('dialog')).not.toBeVisible();
}

/** Adiciona uma seção `text` completa (título + corpo) e salva o rascunho. */
export async function addTextSection(page: Page, title: string, body: string): Promise<void> {
  await addSection(page, 'text');
  await openSectionDialog(page, 'Nova seção (ainda não salva)');
  await fillTranslatedField(page, 'Título', 'Português (Brasil)', title);
  await fillTranslatedField(page, 'Conteúdo', 'Português (Brasil)', textDocument(body));
  await closeSectionDialog(page);
  await saveDraft(page);
}

/** Salva o rascunho e espera a confirmação da sessão. */
export async function saveDraft(page: Page): Promise<void> {
  await page.getByRole('button', { name: 'Salvar rascunho' }).click();
  await expect(page.getByText('Rascunho salvo.')).toBeVisible();
}

/** Publica o rascunho salvo (exige `home.aprovar` — semente demo tem o conjunto completo). */
export async function publishHome(page: Page): Promise<void> {
  await page.getByRole('button', { name: 'Publicar home' }).click();
  await expect(page.getByText(/Home publicada \(versão \d+\)\./)).toBeVisible();
}

/** Resumos das seções na **ordem** da lista (a lista é o documento). */
export async function sectionSummaries(page: Page): Promise<string[]> {
  return page.locator('[data-home-section]').evaluateAll((sections) =>
    sections.map((section) => {
      const summary = section.querySelector('p');

      return (summary?.textContent ?? '').trim();
    }),
  );
}

/** Uma seção da lista pelo resumo (título) do documento. */
export function sectionBySummary(page: Page, summary: string) {
  return page.locator('[data-home-section]').filter({ hasText: summary });
}

/** Aciona um submit do editor por **teclado** (foco + Enter) e espera a navegação. */
export async function submitByKeyboard(page: Page, label: string, summary?: string): Promise<void> {
  const scope = summary === undefined ? page : sectionBySummary(page, summary);
  const control = scope.getByRole('button', { name: label, exact: true });

  await control.focus();

  await Promise.all([page.waitForURL(/\/home$/), control.press('Enter')]);
}

/** Aciona um submit do editor pelo **ponteiro** e espera a navegação. */
export async function submitByPointer(page: Page, label: string, summary?: string): Promise<void> {
  const scope = summary === undefined ? page : sectionBySummary(page, summary);

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