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("Finishing unchanged Markdown preserves its paragraph subtree", WEB, async ({ t3, app, screen, browser }) => {
  await browser.addInitScript(() => {
    const state = { promotions: 0, duplicateParagraphRenders: 0, events: [] as string[] };
    Object.assign(window, { markdownProof: state });
    function name(node: any): string {
      const type = node.type;
      return type?.displayName || type?.type?.name || type?.render?.name || type?.name || "";
    }
    function visit(node: any, promotion = false): void {
      for (; node; node = node.sibling) {
        const performed = [0, 1, 11, 14, 15].includes(node.tag) && Boolean(node.flags & 1);
        const current = node.memoizedProps;
        const previous = node.alternate?.memoizedProps;
        const promoted = name(node).includes("MarkdownSource") && previous &&
          current.text === previous.text && previous.cache === false && current.cache === true;
        if (promoted) {
          state.promotions++;
          state.events.push(`Unchanged block finished: ${JSON.stringify(current.text)}`);
        }
        if (performed && name(node).includes("MarkdownParagraph") && (promotion || promoted)) {
          state.duplicateParagraphRenders++;
          state.events.push("Paragraph subtree rendered again during cache promotion");
        }
        const skipped = node.alternate !== null && node.child === node.alternate.child && !performed;
        if (node.child && !skipped) visit(node.child, promotion || promoted);
      }
    }
    Object.assign(window, { __REACT_DEVTOOLS_GLOBAL_HOOK__: {
      supportsFiber: true, renderers: new Map(), inject: () => 1, checkDCE() {},
      onCommitFiberUnmount() {}, onPostCommitFiberRoot() {},
      onCommitFiberRoot(_id: unknown, root: any) { visit(root.current.child); },
    }});
  });
  const recording = `${APP_DIR}/apps/server/scripts/dev-replay/showcase_transcript.ndjson`;
  const original = await readFile(recording, "utf8");
  const entries: object[] = [{ type: "expect_outbound", frame: { kind: "request", method: "session/prompt", params: "<any>" } }];
  for (let i = 1; i <= 30; i++) entries.push({ type: "emit_inbound", afterMs: 700, frame: {
    kind: "notification", method: "session/update", params: { sessionId: "dev-replay-session", update: {
      sessionUpdate: "agent_message_chunk", content: { type: "text", text: `Paragraph ${i} is short.\n\n` }
    } }
  } });
  entries.push({ type: "emit_inbound", afterMs: 1500, frame: { kind: "response", method: "session/prompt", result: { stopReason: "end_turn" } } });
  await writeFile(recording, entries.map(e => JSON.stringify(e)).join("\n") + "\n");
  try {
  await t3.project("Markdown demo", { "src/math.ts": "export const sum = 1 + 1;\n" });
  await t3.open();
  await screen.getByRole("textbox").fill("Stream thirty short paragraphs");
  await screen.getByRole("textbox").press("Enter");
  await screen.getByText("Paragraph 30 is short.", { exact: false }).waitFor({ state: "visible" });
  await screen.getByRole("button", "Stop generation").waitFor({ state: "hidden" });
  await browser.evaluate(() => {
    const state = (window as any).markdownProof;
    const panel = document.createElement("pre");
    panel.id = "markdown-render-evidence";
    panel.style.cssText = "position:fixed;bottom:16px;left:16px;right:16px;z-index:99999;background:#101827;color:#fff;border:2px solid #8196b5;border-radius:8px;padding:18px;font:14px/1.6 monospace;white-space:pre-wrap;max-height:260px;overflow:auto";
    panel.textContent = `REACT COMMIT OBSERVER — real replay turn\nUnchanged blocks promoted to cache: ${state.promotions}\nParagraph renders during those promotions: ${state.duplicateParagraphRenders}\n\n${state.events.slice(0, 2).join("\n")}\n(${state.events.length} observer events total)`;
    document.body.append(panel);
  });
  await app.screenshot("unchanged-block-render-count");
  const result = await browser.evaluate(() => (window as any).markdownProof);
  const threadPath = await browser.evaluate(() => location.pathname);
  await app.open("/settings/general");
  await app.open(threadPath);
  await screen.getByText("Paragraph 30 is short.", { exact: false }).waitFor({ state: "visible" });
  await app.screenshot("remounted-content");
  expect(await browser.evaluate(() => Array.from(document.querySelectorAll(".chat-markdown p")).filter(p => /^Paragraph \d+ is short\.$/.test(p.textContent ?? "")).length)).toBe(30);
  expect(result.promotions).toBeGreaterThanOrEqual(29);
  expect(result.duplicateParagraphRenders).toBe(0);
  } finally { await writeFile(recording, original); }
});
