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

test("Pasted CRLF and CR preserve blank lines and caret, focused and blurred", WEB, async ({t3, app, screen, browser}) => {
  const project = await t3.project("paste-demo");
  await t3.thread({project, title: "Paste line endings", messages: ["Ready for paste verification"]});
  await t3.open();
  await screen.getByRole("button", "Paste line endings, Done, paste-demo").tap();
  const editor = browser.locator('.tiptap[contenteditable="true"]');
  const results: Array<{label: string; paragraphs: string[]; fence: string | null; caret: number[]}> = [];
  const clear = async () => {
    await editor.tap();
    await browser.keyboard.press("ControlOrMeta+a");
    await browser.keyboard.press("Backspace");
    // A read between clear and paste makes every sample start from verified empty state.
    const text = await browser.evaluate(() => document.querySelector('.tiptap[contenteditable="true"]')!.textContent);
    if (text !== "") throw new Error(`Composer did not clear: ${JSON.stringify(text)}`);
  };
  const paste = async (text: string, blurred = false) => {
    await browser.evaluate(({text, blurred}) => {
      const target = blurred ? document.body : document.querySelector('.tiptap[contenteditable="true"]')!;
      if (blurred && document.activeElement?.closest('[contenteditable="true"]')) throw new Error("Paste target still focused");
      const data = new DataTransfer(); data.setData("text/plain", text);
      target.dispatchEvent(new ClipboardEvent("paste", {clipboardData: data, bubbles: true, cancelable: true}));
    }, {text, blurred});
  };
  const capture = async (label: string, caret: number[] = []) => {
    const state = await browser.evaluate(({label, caret}) => {
      const root = document.querySelector('.tiptap[contenteditable="true"]')!;
      const paragraphs = Array.from(root.querySelectorAll('p')).map(p => p.textContent ?? "");
      const fence = root.querySelector('pre code')?.textContent ?? root.querySelector('pre')?.textContent ?? null;
      let panel = document.getElementById('paste-observation');
      if (!panel) {panel = document.createElement('pre'); panel.id='paste-observation'; document.body.append(panel);}
      panel.style.cssText='position:fixed;right:24px;top:70px;z-index:99999;background:#111827;color:#fff;border:1px solid #94a3b8;padding:16px;font:16px monospace;max-width:650px;white-space:pre-wrap;pointer-events:none';
      panel.textContent = 'DOM observation — '+label+'\nParagraph text: '+JSON.stringify(paragraphs)+'\nFence text: '+JSON.stringify(fence)+'\nCaret paragraph after Up, Up, Down, Down: '+JSON.stringify(caret)+'\n(0-based; CR shown as \\r, LF as \\n)';
      return {label, paragraphs, fence, caret};
    }, {label, caret});
    results.push(state);
    await app.screenshot(label);
  };
  for (const [name,text] of [["lf-control","x\n\ny"],["crlf","x\r\n\r\ny"],["standalone-cr","x\r\ry"]] as const) {
    for (const blurred of [false,true]) {
      await clear();
      if (blurred) {
        // Click the conversation's actual background, then dispatch paste on body, never the editor.
        const point = await browser.evaluate(() => {
          const root = document.querySelector('.tiptap[contenteditable="true"]')!;
          const rect = root.getBoundingClientRect();
          return {x: rect.x + rect.width/2, y: rect.y - 100};
        });
        await browser.mouse.move(point.x, point.y);
        await browser.mouse.down();
        await browser.mouse.up();
      }
      await paste(text, blurred);
      await expect(editor).toBeFocused();
      await browser.keyboard.press("ControlOrMeta+End");
      const caret: number[] = [];
      for (const key of ['ArrowUp','ArrowUp','ArrowDown','ArrowDown']) {
        await browser.keyboard.press(key);
        caret.push(await browser.evaluate(() => {
          const root = document.querySelector('.tiptap[contenteditable="true"]')!;
          const node = window.getSelection()?.anchorNode;
          const p = node instanceof Element ? node.closest('p') : node?.parentElement?.closest('p');
          return Array.from(root.querySelectorAll('p')).indexOf(p as HTMLParagraphElement);
        }));
      }
      await capture(`${name}-${blurred ? 'blurred-body-paste' : 'focused'}`, caret);
    }
  }
  await clear();
  await paste('```\n\n```');
  const code = browser.locator('.tiptap pre code');
  await code.tap();
  await browser.keyboard.press('ControlOrMeta+Home');
  await paste('x\r\n\r\ny');
  await capture('crlf-code-fence');
  // All captures precede the verdict so a base failure cannot hide another changed path.
  const lines = results.filter(r => r.fence === null);
  expect(lines.map(r => r.paragraphs)).toEqual(lines.map(() => ['x','','y']));
  expect(results.at(-1)!.fence).toBe('x\n\ny');
  expect(lines.map(r => r.caret)).toEqual(lines.map(() => [1,0,1,2]));
});
