import { DatabaseSync } from "node:sqlite";
import { expect } from "e2e";
import { test, WEB, makeState, runPromise } from "./t3.ts";
import { T3_HOME } from "../e2e.config.ts";

function activeUsage(threadId: string) {
  const db = new DatabaseSync(`${T3_HOME}/userdata/statev2.sqlite`, { readOnly: true });
  try {
    const rows = db.prepare("SELECT payload_json FROM orchestration_v2_projection_provider_threads WHERE thread_id = ? ORDER BY updated_at DESC").all(threadId);
    return rows.map(row => JSON.parse(String(row.payload_json))).find(row => row.providerInstanceId === "openCodeAcp")?.contextUsage;
  } finally { db.close(); }
}
function tokens(n: number) {
  if (n < 1000) return String(Math.round(n));
  if (n < 10000) return `${(n / 1000).toFixed(1).replace(/\.0$/, "")}k`;
  if (n < 999500) return `${Math.round(n / 1000)}k`;
  return `${(n / 1000000).toFixed(1).replace(/\.0$/, "")}m`;
}

test("Context meter follows the active provider conversation", WEB, async ({ t3, app, screen, browser }) => {
  const project = await t3.project("demo", { "README.md": "# Demo\nA small demo project for verifying provider handoffs.\n" });
  const { cli } = makeState(T3_HOME);
  const launched = await runPromise(cli(["thread", "start", project, "Describe README.md in one sentence.", "--title", "Context meter handoff", "--provider", "pi", "--model", "anthropic/claude-haiku-5-5", "--wait", "--json"]));
  const { threadId } = JSON.parse(launched.stdout);
  await t3.open({ threadId });
  await screen.getByText("Changes", { exact: true }).secondaryTap();
  await screen.getByRole("menuitemcheckbox", "Context window", { exact: true }).tap();
  await browser.keyboard.press("Escape");
  await app.screenshot("pi-before-handoff");
  await screen.getByRole("button", "Haiku 5.5", { exact: false }).tap();
  await screen.getByRole("button", "OpenCode (ACP)", { exact: true }).tap();
  await screen.getByRole("option", "Anthropic/Claude Haiku 5.5", { exact: false }).tap();
  await browser.keyboard.press("Escape");
  await screen.getByTestId("composer-editor").fill("Reply with the single word: ok");
  await screen.getByTestId("composer-editor").press("Enter");
  await screen.getByText("ok", { exact: true }).waitFor({ state: "visible" });
  await screen.getByRole("button", "Stop generation").waitFor({ state: "hidden" });
  const usage = activeUsage(threadId);
  if (!usage) throw new Error("OpenCode did not report conversation usage");
  console.log("ACTIVE CONVERSATION USAGE", usage);
  await browser.locator('[aria-label^="Context:"]').hover();
  await screen.getByText(/of 1,000,000 tokens/).waitFor({ state: "visible" });
  await browser.evaluate(async () => {
    await Promise.all(document.getAnimations().filter(a => a.effect?.getComputedTiming().iterations !== Infinity).map(a => a.finished.catch(() => {})));
  });
  await app.screenshot("after-handoff");
  const liveMeter = await browser.locator('[aria-label^="Context:"]').textContent();
  await browser.reload();
  await browser.locator('[aria-label^="Context:"]').hover();
  await screen.getByText(/of 1,000,000 tokens/).waitFor({ state: "visible" });
  await browser.evaluate(async () => {
    await Promise.all(document.getAnimations().filter(a => a.effect?.getComputedTiming().iterations !== Infinity).map(a => a.finished.catch(() => {})));
  });
  await app.screenshot("after-reload");
  const expected = `${tokens(usage.usedTokens)} / ${tokens(usage.maxTokens)}`;
  await expect(liveMeter).toContain(expected);
  await expect(screen.getByText(expected, { exact: true })).toBeVisible();
});
