import { expect } from "e2e";
import { execFileSync } from "node:child_process";
import { test, WEB } from "./t3.ts";

const azure = (action: string, ...args: string[]) => execFileSync("python3", [process.env.PROOF_SCRATCH_DIR + "/azure-driver.py", action, ...args], { encoding: "utf8" }).trim();
const pause = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
async function settled() {
  for (let n = 0; n < 90; n++) {
    const s = JSON.parse(azure("status"));
    if (s.evaluation === "rejected" || s.evaluation === "approved") return s;
    await pause(5000);
  }
  throw new Error("Azure build validation did not settle");
}

test("Azure build validation renders checks and wakes a watching replay agent", WEB, async ({ t3, app, screen, browser }) => {
  const project = await t3.project("Build validation proof");
  const pr = JSON.parse(azure("seed", project));
  try {
    const thread = await t3.thread({ project, title: "Watch required build validation", messages: ["Watch the pull request while its required build validation runs."] });
    await t3.open(thread);
    await screen.getByRole("heading", "Watch required build validation").waitFor({ timeout: 60000 });
    await browser.evaluate(async ({ threadId, pr }) => {
      const ws = new WebSocket(location.origin.replace(/^http/, "ws") + "/ws?orchestrationProtocol=2");
      await new Promise((resolve, reject) => { ws.onopen = resolve; ws.onerror = reject; });
      const call = (tag: string, payload: unknown) => new Promise<any>((resolve, reject) => {
        const id = crypto.randomUUID();
        ws.onmessage = e => {
          const messages = JSON.parse(e.data);
          for (const m of Array.isArray(messages) ? messages : [messages]) {
            if (m._tag === "Ping") ws.send(JSON.stringify({ _tag: "Pong" }));
            if (m.requestId === id && m._tag === "Exit") {
              if (m.exit._tag === "Success") resolve(m.exit.value); else reject(new Error(JSON.stringify(m.exit)));
            }
          }
        };
        ws.send(JSON.stringify({ _tag: "Request", id, tag, payload, headers: [] }));
      });
      await call("orchestration.dispatchCommand", { type: "thread.pull-request.watch", commandId: crypto.randomUUID(), threadId, host: pr.host, repository: pr.repository, number: pr.number, watching: true, link: { url: pr.url, source: "agent" } });
      ws.close();
      const entities = await import("/src/state/entities.ts");
      const p = entities.readProjects().find((p: any) => p.title === "Build validation proof");
      const { useRightPanelStore } = await import("/src/rightPanelStore.ts");
      useRightPanelStore.getState().openPullRequest({ environmentId: p.environmentId, threadId }, { projectId: p.id, host: pr.host, repository: pr.repository, number: pr.number, url: pr.url });
    }, { threadId: thread.threadId, pr });
    await screen.getByText("Required build validation proof", { exact: true }).last().waitFor({ timeout: 60000 });
    await browser.evaluate(() => { (document.activeElement as HTMLElement)?.blur(); });
    await app.screenshot("pending-validation");
    await settled();
    await pause(145000);
    await app.screenshot("failed-validation-and-wake");
    const failedText = await browser.evaluate(() => document.body.innerText);
    const failedWake = failedText.includes("Checks failed");
    const failedCheck = /checks? failed|1 failed/i.test(failedText);
    azure("success");
    await settled();
    await pause(145000);
    await app.screenshot("successful-validation-and-wake");
    const passedText = await browser.evaluate(() => document.body.innerText);
    const passedWake = /All 1 required check passed/.test(passedText);
    const passedCheck = /checks? passed|1 passed/i.test(passedText);
    console.log(JSON.stringify({ failedWake, failedCheck, passedWake, passedCheck }));
    await expect(failedWake && failedCheck && passedWake && passedCheck).toBe(true);
  } finally { azure("cleanup"); }
});
