import { expect } from "e2e";
import { chromium } from "playwright-core";
import { writeFile } from "node:fs/promises";
import { createServer } from "node:http";
import { test, WEB } from "./t3.ts";

test("Mouse history stays in the right panel", WEB, async ({ t3, app, screen, browser }) => {
  const fixture = createServer((req, res) => {
    const n = Number(req.url?.slice(1)) || 1;
    res.setHeader("Content-Type", "text/html");
    res.end(`<html><title>Page ${n}</title><body style="background:#ecf3fb;color:#17304e;font:24px sans-serif;padding:24px"><h1>Page ${n}</h1><a href="/${n+1}" style="display:block;padding:30px;background:#b9d7fa">Next page</a><p>Synthetic browser history fixture</p></body></html>`);
  });
  await new Promise<void>(r => fixture.listen(19382, "127.0.0.1", r));
  const connected = await chromium.connectOverCDP("http://127.0.0.1:19282");
  const failures: string[] = [];
  try {
    const project = await t3.project("Navigation demo", { "hello.txt": "Hello\n" });
    await t3.thread({ project, title: "Thread A", messages: ["First"] });
    await t3.thread({ project, title: "Thread B", messages: ["Second"] });
    await t3.open();
    await screen.getByText("Thread A", { exact: true }).last().tap();
    await screen.getByText("Thread B", { exact: true }).last().tap();
    const currentUrl = await browser.url();
    const page = connected.contexts().flatMap(c => c.pages()).find(p => p.url() === currentUrl)!;
    const cdp = await page.context().newCDPSession(page);
    await page.getByRole("button", { name: "Toggle right panel", exact: true }).click();
    await page.getByRole("button", { name: /^Browser/ }).click();
    const address = page.locator("[data-preview-url-input]");
    await address.fill("http://127.0.0.1:19382/1");
    await address.press("Enter");
    const waitPage = (n: number) => page.waitForFunction((n) => (document.querySelector("[data-preview-url-input]") as HTMLInputElement)?.value.endsWith("/" + n), n);
    await waitPage(1);
    const canvas = page.locator("[data-server-browser-surface] canvas");
    await canvas.waitFor();
    for (const n of [2,3]) { await canvas.click({position:{x:100,y:165}}); await waitPage(n); }
    const threadB = page.url();
    const thumb = async (x: number, y: number, button: "back"|"forward") => {
      await cdp.send("Input.dispatchMouseEvent", {type:"mouseMoved",x,y});
      await cdp.send("Input.dispatchMouseEvent", {type:"mousePressed",x,y,button,buttons:button === "back" ? 8 : 16,clickCount:1});
      await cdp.send("Input.dispatchMouseEvent", {type:"mouseReleased",x,y,button,buttons:0,clickCount:1});
      await page.waitForTimeout(700);
    };
    const record = async (label: string, point: {x:number,y:number}, browserExpected?: number) => {
      await thumb(point.x,point.y,"back");
      const stayed = page.url() === threadB;
      if (!stayed) failures.push(label + ": Back changed main thread");
      if (stayed && browserExpected !== undefined && !(await address.inputValue()).endsWith("/"+browserExpected)) failures.push(label+": Browser did not go back");
      if(stayed && browserExpected !== undefined) await page.locator("[data-active-tab=true]").filter({hasText:"Page "+browserExpected}).waitFor();
      await app.screenshot(label+"-back");
      await thumb(point.x,point.y,"forward");
      if (page.url() !== threadB) failures.push(label+": Forward changed main thread");
      if(browserExpected !== undefined && page.url() === threadB) {
        await page.getByRole("button",{name:/^(Take|Release) control$/}).waitFor();
        await page.locator("[data-active-tab=true]").filter({hasText:"Page 3"}).waitFor();
      }
      await app.screenshot(label+"-forward");
      if(page.url() !== threadB) await page.goto(threadB);
    };
    const center = async (locator: ReturnType<typeof page.locator>) => { const b=(await locator.boundingBox())!; return {x:b.x+b.width/2,y:b.y+b.height/2}; };
    await app.screenshot("browser-three-pages");
    await page.mouse.click(430,350);
    const addon = page.locator("[data-slot=input-group]").filter({has:address}).locator("[data-slot=input-group-addon]");
    const ab = (await addon.boundingBox())!;
    const ap = {x:ab.x+ab.width-2,y:ab.y+ab.height/2};
    const hit = await page.evaluate(({x,y}) => document.elementFromPoint(x,y)?.getAttribute("data-slot"),ap);
    if(hit !== "input-group-addon") throw new Error("Padding target was not the address addon: "+hit);
    await cdp.send("Input.dispatchMouseEvent",{type:"mouseMoved",...ap});
    await cdp.send("Input.dispatchMouseEvent",{type:"mousePressed",...ap,button:"back",buttons:8,clickCount:1});
    const focused = await address.evaluate(e=>e===document.activeElement);
    if(focused) failures.push("Address-addon padding focused the URL input on mouse Back down");
    console.log("ADDON",{hit,focused});
    await app.screenshot("address-addon-padding-held");
    await cdp.send("Input.dispatchMouseEvent",{type:"mouseReleased",...ap,button:"back",buttons:0,clickCount:1});
    await page.waitForTimeout(700);
    await thumb(ap.x,ap.y,"forward");
    if(page.url() !== threadB) await page.goto(threadB);
    await record("browser-address",await center(address),2);
    await record("browser-tab",await center(page.locator("[data-active-tab=true]")),2);
    await writeFile(project+"/hello.txt","Hello from the changed file\nA second line\n");
    await page.getByRole("button",{name:"Add panel surface",exact:true}).click();
    await page.getByRole("menuitem",{name:/^Diff/}).click();
    await page.getByRole("button",{name:"Expand hello.txt",exact:true}).click();
    await page.getByRole("button",{name:"Collapse hello.txt",exact:true}).waitFor();

    await app.screenshot("diff-ready");
    const panel = page.locator("[data-workspace-area=panel]");

    await record("diff-content",{x:1000,y:330});
    await record("diff-tab",await center(page.locator("[data-active-tab=true]")));
    await page.locator("[data-active-tab=true]").click({button:"right"});
    const menu = page.getByRole("menu"); await menu.waitFor();
    await app.screenshot("diff-context-menu-ready");
    await record("diff-context-menu",await center(menu));
    await page.keyboard.press("Escape");
    await thumb(430,350,"back");
    if(page.url() === threadB) failures.push("Main-chat Back did not change threads");
    await app.screenshot("main-chat-back");
    await thumb(430,350,"forward");
    if(page.url() !== threadB) failures.push("Main-chat Forward did not restore Thread B");
    await app.screenshot("main-chat-forward");
    console.log("OBSERVED",failures);
    expect(failures).toEqual([]);
  } finally { await connected.close(); await new Promise<void>(r => fixture.close(()=>r())); }
});
