import { expect, test } from '@playwright/test';
import { gotoExpecting, KEY_PAGES } from './support/portal';

/**
 * @intent História 06 — alvos mínimos (`histories/06-alvos-minimos.md`).
 *
 * @description Mínimo WCAG 2.2 AA (SC 2.5.8) de 24×24 em qualquer viewport; a casa exige
 *              ≥44×44 em ponteiro grosso. Exceção do SC (link em linha dentro de texto) é
 *              detectada (display `inline` com prosa ao redor) — nunca silenciada em massa.
 */
const INTERACTIVE_SELECTOR =
  'a[href], button, input:not([type="hidden"]), select, textarea, summary, [role="button"], [role="link"]';

type Offender = {
  readonly selector: string;
  readonly width: number;
  readonly height: number;
};

test.describe('História 06 — Alvos mínimos', () => {
  test('todo alvo visível respeita o mínimo do ponteiro', async ({ page }, testInfo) => {
    const minimum = testInfo.project.name === 'portal-mobile' ? 44 : 24;

    for (const keyPage of KEY_PAGES) {
      await gotoExpecting(page, keyPage.path, keyPage.status);

      const offenders = await page.evaluate(
        ({ selector, minimum: min }) => {
          const describe = (element: Element): string => {
            const id = element.id !== '' ? `#${element.id}` : '';
            const classes = element.className !== '' ? `.${String(element.className).split(' ').join('.')}` : '';
            const text = (element.textContent ?? '').trim().slice(0, 24);

            return `${element.tagName.toLowerCase()}${id}${classes} "${text}"`;
          };

          const isInlineProseLink = (element: Element): boolean => {
            if (element.tagName.toLowerCase() !== 'a') {
              return false;
            }

            if (getComputedStyle(element).display !== 'inline') {
              return false;
            }

            const parentText = element.parentElement?.textContent?.trim() ?? '';

            return parentText.length > (element.textContent?.trim().length ?? 0) + 4;
          };

          return Array.from(document.querySelectorAll(selector))
            .filter((element) => {
              const box = element.getBoundingClientRect();

              if (box.width === 0 || box.height === 0) {
                return false;
              }

              if (getComputedStyle(element).visibility === 'hidden') {
                return false;
              }

              return !isInlineProseLink(element);
            })
            .map((element) => {
              const box = element.getBoundingClientRect();

              return {
                selector: describe(element),
                width: Math.round(box.width),
                height: Math.round(box.height),
              };
            })
            .filter((target: Offender) => target.width < min || target.height < min);
        },
        { selector: INTERACTIVE_SELECTOR, minimum },
      );

      expect(
        offenders,
        `${keyPage.path} (mínimo ${minimum}px): ${JSON.stringify(offenders)}`,
      ).toEqual([]);
    }
  });
});
