import { expect, test, type Locator, type Page } from '@playwright/test';
import { createBrowserWorkspace } from './common';

const liveScientific = process.env.LEARNITIVE_SCIENTIFIC_RUNTIME_LIVE === '1';
const liveCpp = process.env.LEARNITIVE_C_CPP_LIVE === '1';

async function openTerminal(page: Page) {
  await page.getByTestId('terminal-open').click();
  const terminal = page.getByTestId('project-terminal');
  await expect(terminal).toBeVisible();
  return { terminal, input: page.getByTestId('terminal-input') };
}

async function runCommand(
  page: Page,
  input: Locator,
  command: string,
  expected: string | RegExp,
  timeout = 60_000,
) {
  const transcript = page.getByTestId('terminal-transcript-line');
  const before = await transcript.count();
  await input.fill(command);
  await input.press('Enter');
  await expect.poll(async () => {
    const count = await transcript.count();
    const output: string[] = [];
    for (let index = before; index < count; index += 1) {
      const line = transcript.nth(index);
      if ((await line.getAttribute('data-terminal-kind')) === 'command') continue;
      output.push(await line.innerText());
    }
    const text = output.join('\n');
    return typeof expected === 'string' ? text.includes(expected) : expected.test(text);
  }, { timeout, message: `Waiting for terminal output after: ${command}` }).toBe(true);
}

test('R14.28.12 scientific runtime doctor is zero-download and browser-aware', async ({ page }, testInfo) => {
  const workspaceName = `scientific-doctor-${testInfo.project.name}-${Date.now()}`;
  await createBrowserWorkspace(page, { workspaceName });
  const { terminal, input } = await openTerminal(page);

  await expect(terminal).not.toContainText('Python: not-loaded');
  await expect(terminal).not.toContainText('R: not-loaded');
  await expect(terminal).not.toContainText('C/C++: not-loaded');
  await expect(terminal).not.toContainText('Browser local');

  await runCommand(page, input, 'runtime doctor', 'Learnitive scientific runtime doctor');
  await expect(terminal).toContainText('No runtimes or packages were downloaded by this check.');
  await expect(terminal).toContainText('WebAssembly');
  await expect(terminal).toContainText('Web Workers');
  await expect(terminal).toContainText('Python · Pyodide');
  await expect(terminal).toContainText('R · webR');
  await expect(terminal).toContainText('C/C++ · Wasmer WASIX');

  // Doctor must not initialize any heavyweight runtime. Runtime state is
  // certified through command output rather than the retired BF12 header pills.
  await runCommand(page, input, 'pyodide info', 'State: not-loaded');
  await runCommand(page, input, 'webr info', 'State: not-loaded');
  await runCommand(page, input, 'wasix info', 'State: not-loaded');

  const capabilities = await page.evaluate(() => ({
    webAssembly: typeof WebAssembly !== 'undefined',
    worker: typeof Worker !== 'undefined',
    fetch: typeof fetch !== 'undefined',
    crossOriginIsolated: globalThis.crossOriginIsolated === true,
  }));
  expect(capabilities.webAssembly).toBe(true);
  expect(capabilities.worker).toBe(true);
  expect(capabilities.fetch).toBe(true);

  if (testInfo.project.name === 'chromium' || testInfo.project.name === 'edge') {
    expect(capabilities.crossOriginIsolated).toBe(true);
  }

  await runCommand(page, input, 'runtime reset all', 'Reset all loaded scientific runtimes');
});

test('R14.28.12 live Python and R execute, create plots, reset and recover', async ({ page }, testInfo) => {
  test.skip(!liveScientific, 'Set LEARNITIVE_SCIENTIFIC_RUNTIME_LIVE=1 to run CDN-backed scientific runtime certification.');
  test.skip(testInfo.project.name !== 'chromium', 'The live heavy-runtime gate runs once in Chromium; doctor preflight covers the full browser matrix.');
  test.setTimeout(360_000);

  const workspaceName = `scientific-live-${Date.now()}`;
  await createBrowserWorkspace(page, { workspaceName });
  const { terminal, input } = await openTerminal(page);

  await runCommand(page, input, 'python -c "print(6*7)"', '42', 180_000);
  await runCommand(page, input, 'pyodide info', 'State: ready');

  await runCommand(
    page,
    input,
    'python -c "import os; os.makedirs(\'figures\',exist_ok=True); import matplotlib; matplotlib.use(\'Agg\'); import matplotlib.pyplot as plt; plt.plot([1,2,3],[1,4,9]); plt.savefig(\'figures/cert-python.png\'); print(\'python-plot-ok\')"',
    'python-plot-ok',
    240_000,
  );
  await runCommand(page, input, 'artifact inspect figures/cert-python.png', 'Kind: plot');

  await runCommand(page, input, 'runtime reset python', 'Reset python runtime');
  await runCommand(page, input, 'pyodide info', 'State: not-loaded');
  await runCommand(page, input, 'python -c "print(\'python-recovered\')"', 'python-recovered', 180_000);

  await runCommand(page, input, 'R -e "cat(6*7)"', '42', 180_000);
  await runCommand(page, input, 'webr info', 'State: ready');
  await runCommand(
    page,
    input,
    'R -e "dir.create(\'figures\', showWarnings=FALSE); png(\'figures/cert-r.png\'); plot(1:3, c(1,4,9)); dev.off(); cat(\'r-plot-ok\')"',
    'r-plot-ok',
    180_000,
  );
  await runCommand(page, input, 'artifact inspect figures/cert-r.png', 'Kind: plot');

  await runCommand(page, input, 'runtime reset r', 'Reset r runtime');
  await runCommand(page, input, 'webr info', 'State: not-loaded');
  await runCommand(page, input, 'R -e "cat(\'r-recovered\')"', 'r-recovered', 180_000);
});

test('R14.28.12 live WASIX utility and C/C++ toolchain certification', async ({ page }, testInfo) => {
  test.skip(!liveScientific || !liveCpp, 'Set LEARNITIVE_SCIENTIFIC_RUNTIME_LIVE=1 and LEARNITIVE_C_CPP_LIVE=1 for the Wasmer/Clang gate.');
  test.skip(testInfo.project.name !== 'chromium', 'The heavyweight Wasmer/Clang gate runs once in Chromium.');
  test.setTimeout(480_000);

  const workspaceName = `scientific-wasi-live-${Date.now()}`;
  await createBrowserWorkspace(page, { workspaceName });
  const { terminal, input } = await openTerminal(page);

  page.on('dialog', (dialog) => void dialog.accept());
  await runCommand(page, input, 'wasix install jaq', 'Loaded browser WASI utility', 180_000);
  await runCommand(page, input, 'jaq -n "6*7"', '42', 120_000);

  await runCommand(page, input, 'wasix install clang', 'Loaded browser Clang toolchain', 300_000);
  await runCommand(page, input, 'clang --version', /Target:/u, 120_000);

  // Use the already-certified Python workspace bridge to create tiny C/C++ sources.
  await runCommand(
    page,
    input,
    'python -c "import os; os.makedirs(\'analysis\',exist_ok=True); nl=chr(10); dq=chr(34); c=\'#include <stdio.h>\'+nl+\'int main(){puts(\'+dq+\'c-live-ok\'+dq+\');return 0;}\'+nl; open(\'analysis/cert.c\',\'w\').write(c); open(\'analysis/cert.cpp\',\'w\').write(\'int main(){return 0;}\'+nl)"',
    'Generated:',
    180_000,
  );
  await runCommand(page, input, 'cat analysis/cert.c', 'c-live-ok');
  await runCommand(page, input, 'cat analysis/cert.cpp', 'int main(){return 0;}');
  await runCommand(page, input, 'clang analysis/cert.c -o build/cert-c.wasm', 'Generated:', 180_000);
  await runCommand(page, input, 'artifact inspect build/cert-c.wasm', 'Kind: binary');
  await runCommand(page, input, 'wasm-run build/cert-c.wasm', 'c-live-ok', 120_000);
  await runCommand(page, input, 'clang++ analysis/cert.cpp -o build/cert-cpp.wasm', 'Generated:', 180_000);
  await runCommand(page, input, 'artifact inspect build/cert-cpp.wasm', 'Kind: binary');
  await runCommand(page, input, 'wasix info', 'State: ready');

  await runCommand(page, input, 'runtime reset wasi', 'Reset wasi runtime');
  await runCommand(page, input, 'wasix info', 'State: not-loaded');
});
