import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { expect, test } from '@playwright/test';
import { loadBrowserWorkspaceFixture } from './common';

const fixtureDirectory = path.join(
  path.dirname(fileURLToPath(import.meta.url)),
  'fixtures/workspaces/live-draft-r4',
);

type LiveDraftSummary = {
  ok: boolean;
  directLua: boolean;
  memfsRecords: boolean;
  pageCount: number;
  fonts: string[];
  hasGlyphs: boolean;
  hasRules: boolean;
  hasWhatsits: boolean;
  hasMultiplePages: boolean;
  reason?: string;
  pdfByteLength: number;
  recordTypes: string[];
  certificate: {
    compileSucceeded: boolean;
    recordArtifactFound: boolean;
    recordArtifactPath?: string;
    recordBytes: number;
    directLuaRecordFound: boolean;
    pageRecords: number;
    pdfBytes: number;
    artifactReadbackAttempts: readonly { path: string; ok: boolean; fileCount: number; error?: string }[];
  };
};

test('R4 browser BusyTeX LuaLaTeX certifies directlua, MEMFS shipout and PDF output without touching manual Compile', async ({
  page,
  browserName,
}) => {
  test.skip(
    browserName !== 'chromium',
    'The R4 feasibility gate exercises the browser BusyTeX runtime once in Chromium.',
  );
  test.setTimeout(300_000);

  const workspaceName = `live-draft-r4-${Date.now()}`;
  await loadBrowserWorkspaceFixture(page, fixtureDirectory, { workspaceName });

  const url = new URL(page.url());
  url.searchParams.set('learnitiveLiveDraftProbe', '1');
  await page.goto(url.toString(), { waitUntil: 'networkidle' });

  await expect
    .poll(() =>
      page.evaluate(() =>
        Boolean(
          (window as unknown as { __learnitiveLiveDraftProbe?: unknown })
            .__learnitiveLiveDraftProbe,
        ),
      ),
    )
    .toBe(true);

  const beforeManualStatus = await page
    .getByTestId('interactive-pdf-preview')
    .getByTestId('interactive-log-status-dot')
    .getAttribute('data-compile-status');

  const result = await page.evaluate(async (wsName): Promise<LiveDraftSummary> => {
    const hook = (
      window as unknown as {
        __learnitiveLiveDraftProbe?: {
          probe: (workspace: string) => Promise<{
            ok: boolean;
            directLua: boolean;
            memfsRecords: boolean;
            pageCount: number;
            fonts: readonly string[];
            hasGlyphs: boolean;
            hasRules: boolean;
            hasWhatsits: boolean;
            hasMultiplePages: boolean;
            reason?: string;
            pdf?: Uint8Array;
            records: readonly { type: string }[];
            certificate: LiveDraftSummary['certificate'];
          }>;
        };
      }
    ).__learnitiveLiveDraftProbe;
    if (!hook) throw new Error('R4 Live Draft probe hook was not installed.');
    const probe = await hook.probe(wsName);
    return {
      ok: probe.ok,
      directLua: probe.directLua,
      memfsRecords: probe.memfsRecords,
      pageCount: probe.pageCount,
      fonts: [...probe.fonts],
      hasGlyphs: probe.hasGlyphs,
      hasRules: probe.hasRules,
      hasWhatsits: probe.hasWhatsits,
      hasMultiplePages: probe.hasMultiplePages,
      ...(probe.reason ? { reason: probe.reason } : {}),
      pdfByteLength: probe.pdf?.byteLength ?? 0,
      recordTypes: [...new Set(probe.records.map((record) => record.type))],
      certificate: probe.certificate,
    };
  }, workspaceName);

  expect(result, result.reason).toMatchObject({
    ok: true,
    directLua: true,
    memfsRecords: true,
  });
  expect(result.pageCount).toBeGreaterThanOrEqual(1);
  expect(result.pdfByteLength).toBeGreaterThan(0);
  expect(result.recordTypes).toEqual(expect.arrayContaining(['runtime', 'page']));
  expect(result.certificate).toMatchObject({
    compileSucceeded: true,
    recordArtifactFound: true,
    directLuaRecordFound: true,
  });
  expect(result.certificate.recordBytes).toBeGreaterThan(0);
  expect(result.certificate.pageRecords).toBeGreaterThanOrEqual(1);
  expect(result.certificate.pdfBytes).toBeGreaterThan(0);
  expect(result.certificate.artifactReadbackAttempts.length).toBeGreaterThanOrEqual(1);

  // R4 must remain invisible to and independent from the authoritative PDF
  // compiler state. The feasibility probe never presses Compile.
  const afterManualStatus = await page
    .getByTestId('interactive-pdf-preview')
    .getByTestId('interactive-log-status-dot')
    .getAttribute('data-compile-status');
  expect(afterManualStatus).toBe(beforeManualStatus);
});

test('R4 Live Draft probe can be cancelled independently', async ({ page, browserName }) => {
  test.skip(browserName !== 'chromium', 'Certified with the Chromium BusyTeX runtime.');
  test.setTimeout(300_000);

  const workspaceName = `live-draft-r4-cancel-${Date.now()}`;
  await loadBrowserWorkspaceFixture(page, fixtureDirectory, { workspaceName });
  const url = new URL(page.url());
  url.searchParams.set('learnitiveLiveDraftProbe', '1');
  await page.goto(url.toString(), { waitUntil: 'networkidle' });

  const outcome = await page.evaluate(async (wsName) => {
    const hook = (
      window as unknown as {
        __learnitiveLiveDraftProbe?: {
          probe: (workspace: string) => Promise<unknown>;
          cancel: () => void;
        };
      }
    ).__learnitiveLiveDraftProbe;
    if (!hook) throw new Error('R4 Live Draft probe hook was not installed.');
    const pending = hook.probe(wsName).then(
      () => 'completed',
      (error: unknown) =>
        error instanceof DOMException && error.name === 'AbortError'
          ? 'cancelled'
          : `error:${error instanceof Error ? error.message : String(error)}`,
    );
    await new Promise((resolve) => setTimeout(resolve, 25));
    hook.cancel();
    return pending;
  }, workspaceName);

  expect(outcome).toBe('cancelled');
  // Cancellation remains isolated; the authoritative compiler was never invoked.
  await expect(
    page.getByTestId('interactive-pdf-preview').getByTestId('interactive-log-status-dot'),
  ).not.toHaveAttribute('data-compile-status', 'running');
});
