import { expect } from "e2e";
import { test, WEB } from "./t3.ts";

test("Deleting a thread preserves navigation made while deletion is pending", WEB, async ({ t3, app, screen, browser }) => {
  const project = await t3.project("Navigation demo");
  await t3.thread({ project, title: "Thread B", messages: ["This is the conversation for Thread B."] });
  await t3.thread({ project, title: "Thread C", messages: ["This is the fallback conversation for Thread C."] });
  await t3.thread({ project, title: "Thread A", messages: ["This is the conversation to delete."] });
  // Hold only the real outgoing delete frame, as a slow connection would; all app code and responses remain real.
  await browser.addInitScript(() => {
    const send = WebSocket.prototype.send;
    const gate = { armed: false, pending: null as null | (() => void), ready: null as null | (() => void) };
    Object.assign(window, { deletionGate: gate });
    WebSocket.prototype.send = function (data) {
      if (gate.armed && typeof data === "string" && data.includes('"thread.delete"')) {
        gate.armed = false;
        gate.pending = () => { send.call(this, data); gate.pending = null; };
        gate.ready?.();
        return;
      }
      return send.call(this, data);
    };
  });
  await browser.emulateMedia({ colorScheme: "dark" });
  await t3.open();
  const thread = (name: string) => screen.getByRole("button", new RegExp(`^${name},`));
  const removeA = async () => {
    await thread("Thread A").tap();
    await thread("Thread A").secondaryTap();
    await screen.getByRole("menuitem", /Delete/).tap();
    await screen.getByRole("button", "Confirm", { exact: true }).tap();
  };
  await removeA();
  await expect(screen.getByText("This is the fallback conversation for Thread C.", { exact: true })).toBeVisible();
  await app.screenshot("ordinary-fallback");
  await t3.thread({ project, title: "Thread A", messages: ["This is the conversation to delete."] });
  await browser.evaluate(() => { (window as any).deletionGate.armed = true; });
  await removeA();
  await browser.evaluate(() => {
    const gate = (window as any).deletionGate;
    return gate.pending ? undefined : new Promise<void>((resolve) => { gate.ready = resolve; });
  });
  await thread("Thread B").tap();
  await screen.getByText("This is the conversation for Thread B.", { exact: true }).waitFor();
  await app.screenshot("opened-B-while-delete-pending");
  // Keep the connection pending long enough to see B before the real request completes.
  await browser.evaluate(() => new Promise<void>((resolve) => {
    setTimeout(() => { (window as any).deletionGate.pending(); resolve(); }, 3000);
  }));
  await thread("Thread A").waitFor({ state: "hidden" });
  // Let the network response and its resulting navigation paint before the outcome capture.
  await browser.evaluate(() => new Promise((resolve) => setTimeout(resolve, 1500)));
  await app.screenshot("after-delete-completes");
  await expect(screen.getByText("This is the conversation for Thread B.", { exact: true })).toBeVisible();
  await expect(thread("Thread A")).toBeHidden();
});
