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

test("Blinking terminal block cursor clears its cell at fractional scale", WEB, async ({ t3, app, screen, browser }) => {
  await browser.addInitScript(() => {
    Object.defineProperty(window, "devicePixelRatio", { get: () => 1.25, configurable: true });
    localStorage.setItem("t3code:theme", "light");
    localStorage.setItem("t3code:client-settings:v1", JSON.stringify({ fontSizeTerminal: 11, fontSizeCode: 11 }));
  });
  const project = await t3.project("cursor-demo");
  await t3.thread({ project, title: "Terminal cursor", messages: ["Ready"] });
  await t3.open();
  await screen.getByRole("button", "Terminal cursor, Done, cursor-demo", { exact: true }).tap();
  await screen.getByRole("button", "Toggle terminal drawer", { exact: true }).tap();
  await browser.locator("canvas").tap();
  await browser.keyboard.type("export PS1='demo $ '; printf '\\033[2J\\033[3;1H\\033[1 q'\n");
  await browser.evaluate(() => new Promise<void>((resolve, reject) => {
    const input = document.querySelector<HTMLTextAreaElement>(".t3-ghostty-input")!;
    const done = () => parseFloat(input.style.top) === 34 && parseFloat(input.style.left) < 100;
    if (done()) return resolve();
    const observer = new MutationObserver(() => {
      if (done()) { observer.disconnect(); clearTimeout(timeout); resolve(); }
    });
    const timeout = setTimeout(() => { observer.disconnect(); reject(new Error("Synthetic prompt did not reach row 3")); }, 10000);
    observer.observe(input, { attributes: true, attributeFilter: ["style"] });
  }));
  await app.screenshot("prompt-ready");
  const off = await browser.evaluate(() => new Promise<{ strayPixels: number; geometry: unknown }>((resolve, reject) => {
    const input = document.querySelector<HTMLTextAreaElement>(".t3-ghostty-input")!;
    const canvas = input.parentElement!.querySelector("canvas")!;
    const ctx = canvas.getContext("2d")!;
    const scale = ctx.getTransform().d;
    const x = Math.ceil((parseFloat(input.style.left) + 2) * scale);
    const top = Math.floor(parseFloat(input.style.top) * scale);
    const height = Math.ceil((parseFloat(input.style.top) + parseFloat(input.style.height)) * scale) - top;
    const original = ctx.fillRect;
    const timeout = setTimeout(() => { ctx.fillRect = original; reject(new Error("No blink-off repaint observed")); }, 10000);
    ctx.fillRect = function (...args) {
      original.apply(this, args);
      queueMicrotask(() => {
        const bg = ctx.getImageData(x + 30, top + 5, 1, 1).data;
        const center = ctx.getImageData(x, top + Math.floor(height / 2), 1, 1).data;
        if (center[0] !== bg[0] || center[1] !== bg[1] || center[2] !== bg[2]) return;
        const pixels = ctx.getImageData(x, top, 3, height).data;
        let strayPixels = 0;
        for (let i = 0; i < pixels.length; i += 4) {
          if (pixels[i] !== bg[0] || pixels[i+1] !== bg[1] || pixels[i+2] !== bg[2]) strayPixels++;
        }
        ctx.fillRect = original;
        clearTimeout(timeout);
        resolve({ strayPixels, geometry: { x, top, height, scale, font: ctx.font, background: [...bg] } });
      });
    };
  }));
  console.log("Blink-off cell", JSON.stringify(off));
  await app.screenshot("cursor-blink-off");
  await browser.evaluate(() => new Promise<void>((resolve) => setTimeout(resolve, 3500)));
  await expect(off.strayPixels).toBe(0);
});
