import assert from "node:assert/strict";
import { setTimeout as delay } from "node:timers/promises";
import postgres from "postgres";

import { loginBrowser, requireOperatorPassword } from "./auth.js";
import { approvedJourneyEnvironment, requiredEnvironment } from "./exact-journey.js";

const webUrl = requiredEnvironment(process.env, "AWP_WEB_URL");
const databaseUrl = requiredEnvironment(process.env, "AWP_TEST_POSTGRES_URL");
const playwrightModule = requiredEnvironment(process.env, "AWP_PLAYWRIGHT_MODULE");
const operatorPassword = requireOperatorPassword();
const { factoryRunId, firstTaskId } = approvedJourneyEnvironment();
const timeoutMs = Number(process.env.AWP_GOLIVE_TIMEOUT_MS ?? "120000");

const sql = postgres(databaseUrl, { max: 1 });
let rows: Array<{
  project_id: string;
  change_set_id: string;
  attempt_id: string;
  tool_name: string | null;
}> = [];
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
  rows = await sql<
    { project_id: string; change_set_id: string; attempt_id: string; tool_name: string | null }[]
  >`
    select
      cs.project_id,
      cs.id as change_set_id,
      a.id as attempt_id,
      a.tool_calls->0->>'name' as tool_name
    from factory_runs fr
    join agent_runs ar
      on ar.factory_run_id = fr.id
     and ar.task_id = fr.task_id
    join attempts a on a.agent_run_id = ar.id
    join change_sets cs
      on cs.producer_attempt_id = a.id
     and cs.task_id = ar.task_id
     and cs.project_id = fr.project_id
    where fr.id = ${factoryRunId}
      and fr.task_id = ${firstTaskId}
      and jsonb_array_length(a.tool_calls) > 0
      and cs.diff ~ E'(^|\n)\+[^+]'
      and cs.diff ~ E'(^|\n)-[^-]'
    order by cs.created_at, cs.id
  `;
  if (rows.length > 0) break;
  await delay(100);
}
await sql.end({ timeout: 5 });
assert.equal(
  rows.length,
  1,
  "the exact first Task must have one ChangeSet with durable tool calls and a two-sided diff",
);
const row = rows[0]!;
assert.ok(row.tool_name, "the producer Attempt must retain a named tool call");

const { chromium } = await import(playwrightModule);
const browser = await chromium.launch({ headless: true });
try {
  const page = await browser.newPage();
  await loginBrowser(page, webUrl, operatorPassword);
  await page.goto(
    `${webUrl}/factory-runs/${encodeURIComponent(factoryRunId)}?project=${encodeURIComponent(row.project_id)}&tab=agent-runs`,
    { waitUntil: "networkidle" },
  );
  const toolCall = page.locator(
    `[data-attempt-id="${row.attempt_id}"] [data-tool-call="${row.tool_name}"]`,
  );
  await toolCall.waitFor();
  await toolCall.getByText(row.tool_name, { exact: true }).waitFor();

  await page.goto(
    `${webUrl}/changesets/${encodeURIComponent(row.change_set_id)}?project=${encodeURIComponent(row.project_id)}&tab=files`,
    { waitUntil: "networkidle" },
  );
  assert.ok((await page.locator(".diff-line.added").count()) > 0);
  assert.ok((await page.locator(".diff-line.removed").count()) > 0);
  assert.equal(await page.locator("pre").count(), 0);
  process.stdout.write(
    `AC-24 PASS: exact FactoryRun ${factoryRunId} ChangeSet ${row.change_set_id} renders named tool call ${row.tool_name} plus semantic added/removed diff lines\n`,
  );
} finally {
  await browser.close();
}
