import { readFile, writeFile } from "node:fs/promises";
import { expect } from "e2e";
import { test, WEB, makeState, runPromise } from "./t3.ts";
import { run } from "./shell.ts";
import { APP_DIR, T3_HOME } from "../e2e.config.ts";

test("OpenCode models stay scoped to their project", WEB, async ({ t3, app, screen, browser }) => {
  const config = {$schema: "https://opencode.ai/config.json", provider: {proof: {npm: "@ai-sdk/openai-compatible", name: "Project proof", options: {baseURL: "http://127.0.0.1:9/v1", apiKey: "synthetic"}, models: {"project-only": {name: "Project Only Model", limit: {context: 32000, output: 4000}}}}}};
  const a = await t3.project("Project A", {"opencode.jsonc": JSON.stringify(config)});
  const b = await t3.project("Project B");
  const settings = JSON.parse(await readFile(T3_HOME + "/userdata/settings.json", "utf8"));
  const providerEnv = Object.fromEntries(settings.providerInstances.opencode.environment.map((e: {name: string, value: string}) => [e.name, e.value]));
  const catalog = async (cwd: string) => {
    const result = await runPromise(run("opencode", ["models"], {cwd, env: {...process.env, ...providerEnv}}));
    return result.stdout.split("\n").filter(line => line.startsWith("proof/") || line.startsWith("control/"));
  };
  console.log("Project A CLI catalog:", await catalog(a));
  console.log("Project B CLI catalog:", await catalog(b));
  await t3.thread({project: a, title: "A existing thread", messages: ["Fixture ready"]});
  await t3.thread({project: b, title: "B isolation thread", messages: ["Fixture ready"]});
  const {cli} = makeState(T3_HOME);
  await runPromise(cli(["thread", "start", a, "Fixture ready", "--title", "A worktree thread", "--provider", "devReplay", "--model", "multi-turn", "--worktree", "main", "--branch", "proof-worktree", "--wait", "--json"]));
  await t3.open();
  const outcomes: boolean[] = [];
  const pause = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
  const capture = async (label: string) => {
    for (let attempt = 0; attempt < 8; attempt++) {
      const first = await app.screenshot(label + "-stability-1");
      await pause(500);
      const second = await app.screenshot(label + "-stability-2");
      if ((await readFile(first)).equals(await readFile(second))) {
        await app.screenshot(label);
        return;
      }
    }
    throw new Error("Capture did not settle: " + label);
  };
  const openPicker = async () => {
    await browser.locator("[data-chat-provider-model-picker]").tap();
    await screen.getByRole("button", "OpenCode", {exact: true}).tap();
    await screen.getByPlaceholder("Search models...").fill("Project Only Model");
    await pause(3000);
  };
  for (const [title, project, label] of [
    ["A existing thread", "Project A", "project-a-thread"],
    ["B isolation thread", "Project B", "project-b-isolation"],
    ["A worktree thread", "Project A", "project-a-worktree"],
  ]) {
    await screen.getByRole("button", title + ", Done, " + project).tap();
    await openPicker();
    await capture(label);
    outcomes.push((await screen.getByRole("option", /Project Only Model/).count()) > 0);
    await browser.keyboard.press("Escape");
  }
  console.log("A thread, B isolation, A worktree model present:", outcomes);
  await expect(outcomes).toEqual([true, false, true]);
});
