import type { Locator, Page } from "playwright";
import { humanDelay } from "@/lib/utils";

function normalizeDraftText(text: string): string {
  return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
}

function isTextInserted(actual: string, expected: string): boolean {
  const a = normalizeDraftText(actual).trim();
  const e = normalizeDraftText(expected).trim();
  if (!e) return true;
  if (a === e) return true;
  if (a.length >= Math.min(e.length, 20)) return true;
  return a.includes(e.slice(0, Math.min(24, e.length)));
}

async function clearEditor(page: Page, editor: Locator) {
  await editor.scrollIntoViewIfNeeded().catch(() => undefined);
  await editor.click();
  await humanDelay(120, 220);
  await page.keyboard.press("Meta+A");
  await page.keyboard.press("Backspace");
  await humanDelay(100, 180);
}

async function pasteTextIntoEditor(page: Page, editor: Locator, text: string): Promise<boolean> {
  try {
    await page.context().grantPermissions(["clipboard-read", "clipboard-write"]);
  } catch {
    // ignore permission errors on some hosts
  }

  try {
    await page.evaluate(async (value) => {
      await navigator.clipboard.writeText(value);
    }, text);
    await editor.click();
    await page.keyboard.press("Meta+v");
    await humanDelay(250, 450);
    return true;
  } catch {
    return page.evaluate((value) => {
      const target =
        document.querySelector('[data-threadtools-editor="true"]') ??
        document.querySelector('[role="dialog"] [contenteditable="true"]') ??
        document.querySelector('[contenteditable="true"][role="textbox"]') ??
        document.querySelector('[contenteditable="true"]');
      if (!(target instanceof HTMLElement)) return false;

      target.focus();
      const dataTransfer = new DataTransfer();
      dataTransfer.setData("text/plain", value);
      const pasted = target.dispatchEvent(
        new ClipboardEvent("paste", {
          clipboardData: dataTransfer,
          bubbles: true,
          cancelable: true,
        })
      );
      return pasted !== false;
    }, text);
  }
}

async function typeWithLineBreaks(page: Page, text: string) {
  const normalized = normalizeDraftText(text);
  const paragraphs = normalized.split(/\n\n+/);

  for (let p = 0; p < paragraphs.length; p++) {
    if (p > 0) {
      await page.keyboard.press("Enter");
      await humanDelay(40, 90);
    }

    const lines = paragraphs[p].split("\n");
    for (let l = 0; l < lines.length; l++) {
      if (l > 0) {
        await page.keyboard.press("Shift+Enter");
        await humanDelay(40, 90);
      }
      if (lines[l]) {
        await page.keyboard.insertText(lines[l]);
        await humanDelay(30, 70);
      }
    }
  }
}

export async function typeIntoEditor(page: Page, editor: Locator, text: string) {
  const normalized = normalizeDraftText(text);
  await clearEditor(page, editor);

  const pasted = await pasteTextIntoEditor(page, editor, normalized);
  if (pasted) {
    const value = await editor.innerText().catch(() => "");
    if (isTextInserted(value, normalized)) return;
  }

  await clearEditor(page, editor);
  await typeWithLineBreaks(page, normalized);

  const value = await editor.innerText().catch(() => "");
  if (!isTextInserted(value, normalized)) {
    await clearEditor(page, editor);
    await editor.click();
    await page.keyboard.insertText(normalized);
  }
}