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

test("Browser automation remains available before opening and after closing the last tab", WEB, async ({ t3, app, screen }) => {
  const agentFile = `${APP_DIR}/apps/server/scripts/dev-replay-agent.ts`;
  const original = await readFile(agentFile, "utf8");
  const injected = original
    .replace('loadSession: true,', 'loadSession: true, mcpCapabilities: { http: true },')
    .replace('sessions.set(sessionId, { cwd,', 'sessions.set(sessionId, { mcpServers: params.mcpServers, cwd,')
    .replace('const turns = loadTurns(session.model);', `
        if (JSON.stringify(params.prompt).includes("Prove browser availability")) {
          const server = { url: process.env.T3_ACP_MCP_ENDPOINT, headers: [{ name: "Authorization", value: process.env.T3_ACP_MCP_AUTHORIZATION }] };
          if (!server.url) throw new Error("No MCP endpoint supplied");
          let rpcId = 0;
          let mcpSession = "";
          const rpc = async (method: string, payload: any) => {
            const response = await fetch(server.url, {
              method: "POST",
              headers: { "content-type": "application/json", accept: "application/json, text/event-stream", ...Object.fromEntries(server.headers.map((h: any) => [h.name, h.value])), ...(mcpSession ? { "mcp-session-id": mcpSession, "mcp-protocol-version": "2025-06-18" } : {}) },
              body: JSON.stringify({ jsonrpc: "2.0", id: ++rpcId, method, params: payload }),
            });
            mcpSession = response.headers.get("mcp-session-id") ?? mcpSession;
            const text = await response.text();
            const data = text.startsWith("event:") || text.startsWith("data:") ? JSON.parse(text.split("\\n").find((l: string) => l.startsWith("data:"))!.slice(5)) : JSON.parse(text);
            if (data.error) throw new Error(JSON.stringify(data.error));
            return data.result;
          };
          await rpc("initialize", { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "browser-proof", version: "1" } });
          const call = async (name: string, args = {}) => {
            const r = await rpc("tools/call", { name, arguments: args });
            if (r.isError) throw new Error(JSON.stringify(r));
            const raw = r.structuredContent ?? JSON.parse(r.content.find((c: any) => c.type === "text").text);
            return raw.result ?? raw;
          };
          const show = async (label: string, r: any) => {
            const text = label + ": available=" + r.available + ", visible=" + r.visible + ", tabId=" + (r.tabId === null ? "null" : "present");
            send({ method: "session/update", params: { sessionId, update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: text + "\\n\\n" } } } });
            await new Promise(resolve => setTimeout(resolve, 1000));
          };
          await show("Before opening", await call("preview_status"));
          const opened = await call("preview_open");
          await show("Opened", opened);
          await call("t3_preview_close", { tabId: opened.tabId });
          await show("After closing last tab", await call("preview_status"));
          const reopened = await call("preview_open");
          await show("Reopened", reopened);
          await call("t3_preview_close", { tabId: reopened.tabId });
          send({ method: "session/update", params: { sessionId, update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "Browser lifecycle complete" } } } });
          return { stopReason: "end_turn" };
        }
        const turns = loadTurns(session.model);`);
  try {
    await writeFile(agentFile, injected);
    const project = await t3.project("browser-proof");
    await t3.thread({ project, title: "Browser availability proof", messages: ["Ready for browser verification"] });
    await t3.open();
    await screen.getByRole("button", "Browser availability proof, Done, browser-proof").tap();
    await screen.getByRole("textbox").fill("Prove browser availability: status, open, close the actual tab, status, reopen.");
    await screen.getByRole("textbox").press("Enter");
    await screen.getByText("Browser lifecycle complete", { exact: false }).first().textContent();
    await screen.getByRole("button", "Browser availability proof, Done, browser-proof").textContent();
    let previous = await app.screenshot("settling");
    let stable = false;
    for (let attempt = 0; attempt < 10; attempt++) {
      await new Promise(resolve => setTimeout(resolve, 500));
      const current = await app.screenshot("browser-lifecycle");
      if ((await readFile(previous)).equals(await readFile(current))) { stable = true; break; }
      previous = current;
    }
    if (!stable) throw new Error("Capture did not settle");
    await expect(screen.getByText("Before opening: available=true, visible=false, tabId=null", { exact: false })).toBeVisible();
    await expect(screen.getByText("After closing last tab: available=true, visible=false, tabId=null", { exact: false })).toBeVisible();
  } finally {
    await writeFile(agentFile, original);
  }
});
