import type { Locator, Page } from "playwright";
import { humanDelay } from "@/lib/utils";
import { shouldRunHeadedForPublish } from "./debug";
import type { DebugRun } from "./debug";
import { captureDebugStep } from "./debug";

export type ComposeBlockReason =
  | "login_redirect"
  | "instagram_reauth"
  | "onboarding_dialog"
  | "editor_not_found";

export interface ComposeReadyResult {
  ready: boolean;
  reason?: ComposeBlockReason;
  message?: string;
}

const IG_CONTINUE_TEXT = "使用 Instagram 帳號繼續登入";
const COMPOSE_PLACEHOLDERS = [
  /有什麼新鮮事/,
  /有什麼新鮮/,
  /在想什麼/,
  /What's new/i,
  /Start a thread/i,
  /串文|貼文|文字/,
];

const COMPOSE_URLS = [
  "https://www.threads.com/",
  "https://www.threads.com/compose",
  "https://www.threads.com/intent/post",
];

export async function dismissBlockingDialogs(page: Page, debug?: DebugRun | null) {
  const actions: Array<() => Promise<void>> = [
    async () => {
      const close = page.getByRole("button", { name: "關閉" }).first();
      if (await close.isVisible({ timeout: 800 }).catch(() => false)) await close.click({ force: true });
    },
    async () => {
      const close = page.locator('[aria-label="關閉"], [aria-label="Close"]').first();
      if (await close.isVisible({ timeout: 800 }).catch(() => false)) await close.click({ force: true });
    },
    async () => {
      const later = page.getByRole("button", { name: /稍後|Not now|取消|Cancel/i }).first();
      if (await later.isVisible({ timeout: 800 }).catch(() => false)) await later.click({ force: true });
    },
    async () => page.keyboard.press("Escape"),
  ];

  for (const action of actions) {
    try {
      await action();
      await humanDelay(300, 600);
    } catch {
      // ignore
    }
  }

  await captureDebugStep(page, debug, "dismiss-dialogs");
}

export async function assessComposeReady(page: Page): Promise<ComposeReadyResult> {
  const url = page.url();
  if (url.includes("/login")) {
    return {
      ready: false,
      reason: "login_redirect",
      message: "Session 已失效，請到設定頁重新登入 Threads",
    };
  }

  const igContinue = page.getByText(IG_CONTINUE_TEXT, { exact: false }).first();
  if (await igContinue.isVisible({ timeout: 1500 }).catch(() => false)) {
    return {
      ready: false,
      reason: "instagram_reauth",
      message:
        "Threads 需要完成 Instagram 授權才能發文。請到設定頁重新登入，並在瀏覽器完成「使用 Instagram 帳號繼續登入」。",
    };
  }

  const dialog = page.locator('[role="dialog"]').first();
  if (await dialog.isVisible({ timeout: 1000 }).catch(() => false)) {
    const text = await dialog.innerText().catch(() => "");
    if (text.includes("加入 Threads") || text.includes("暢所欲言")) {
      return {
        ready: false,
        reason: "onboarding_dialog",
        message:
          "Threads 顯示未完成設定的彈窗，無法發文。請到設定頁重新登入並完成 Instagram 授權。",
      };
    }
  }

  return { ready: true };
}

async function tryResolveInstagramReauth(page: Page, debug?: DebugRun | null): Promise<boolean> {
  const igContinue = page.getByText(IG_CONTINUE_TEXT, { exact: false }).first();
  if (!(await igContinue.isVisible({ timeout: 2000 }).catch(() => false))) {
    return true;
  }

  await captureDebugStep(page, debug, "instagram-reauth-detected");

  if (!(await shouldRunHeadedForPublish())) {
    return false;
  }

  await igContinue.click().catch(() => undefined);
  await humanDelay(2000, 3500);
  await captureDebugStep(page, debug, "instagram-reauth-clicked");

  const deadline = Date.now() + 180000;
  while (Date.now() < deadline) {
    if (page.url().includes("instagram.com")) {
      await page.waitForTimeout(2000);
      continue;
    }

    if (!page.url().includes("threads")) {
      await page.waitForTimeout(2000);
      continue;
    }

    await dismissBlockingDialogs(page, debug);
    const ready = await assessComposeReady(page);
    if (ready.ready) return true;
    await page.waitForTimeout(2000);
  }

  return false;
}

export async function openComposeSurface(page: Page, debug?: DebugRun | null): Promise<ComposeReadyResult> {
  for (const url of COMPOSE_URLS) {
    await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 }).catch(() => undefined);
    await humanDelay(2000, 3500);
    await captureDebugStep(page, debug, "compose-nav", { url });

    let ready = await assessComposeReady(page);
    if (!ready.ready && ready.reason === "instagram_reauth") {
      const resolved = await tryResolveInstagramReauth(page, debug);
      if (!resolved) return ready;
      ready = await assessComposeReady(page);
    }
    if (!ready.ready) continue;

    await dismissBlockingDialogs(page, debug);
    ready = await assessComposeReady(page);
    if (!ready.ready) continue;

    if (url.endsWith("/")) {
      const opened = await clickCreateButton(page);
      await humanDelay(2000, 3500);
      await captureDebugStep(page, debug, "after-create-click", { opened });
    }

    const editor = await findComposeEditor(page, debug, 10000);
    if (editor) {
      return { ready: true };
    }
  }

  return {
    ready: false,
    reason: "editor_not_found",
    message: composeFailureMessage("editor_not_found"),
  };
}

async function clickCreateButton(page: Page): Promise<boolean> {
  const clicked = await page.evaluate(() => {
    const labels = ["建立", "Create", "新串文", "New thread"];
    for (const label of labels) {
      const marker =
        document.querySelector(`[aria-label="${label}"]`) ??
        document.querySelector(`[title="${label}"]`);
      if (!marker) continue;

      let node: Element | null = marker;
      for (let depth = 0; depth < 12 && node; depth++) {
        if (node instanceof HTMLAnchorElement && node.href) {
          node.click();
          return true;
        }
        if (node instanceof HTMLElement) {
          const role = node.getAttribute("role");
          const tabIndex = node.getAttribute("tabindex");
          if (role === "button" || role === "link" || tabIndex === "0") {
            node.click();
            return true;
          }
        }
        node = node.parentElement;
      }

      if (marker instanceof HTMLElement) {
        marker.click();
        return true;
      }
    }
    return false;
  });

  if (clicked) return true;

  const createSelectors = [
    'a[href*="/compose"]',
    'a[href*="intent/post"]',
    '[aria-label="建立"]',
    '[aria-label="Create"]',
    'div[role="button"]:has-text("建立")',
    'div[role="button"]:has-text("Create")',
  ];

  for (const selector of createSelectors) {
    const target = page.locator(selector).first();
    if (await target.isVisible({ timeout: 1200 }).catch(() => false)) {
      await target.click({ force: true });
      return true;
    }
  }

  return false;
}

export async function findComposeEditor(
  page: Page,
  debug?: DebugRun | null,
  timeoutMs = 18000
): Promise<Locator | null> {
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    const editor = await locateComposeEditor(page);
    if (editor) {
      await captureDebugStep(page, debug, "editor-found");
      return editor;
    }
    await page.waitForTimeout(600);
  }

  await captureDebugStep(page, debug, "editor-not-found", {
    textboxCount: await page.getByRole("textbox").count(),
    contentEditableCount: await page.locator('[contenteditable="true"]').count(),
    dialogCount: await page.locator('[role="dialog"]').count(),
    url: page.url(),
  });

  return null;
}

async function locateComposeEditor(page: Page): Promise<Locator | null> {
  const selectors = [
    '[role="dialog"] [contenteditable="true"][role="textbox"]',
    '[role="dialog"] [contenteditable="true"]',
    '[contenteditable="true"][role="textbox"]',
    '[contenteditable="true"][aria-label*="文字"]',
    '[contenteditable="true"][aria-label*="text"]',
    '[contenteditable="true"][aria-label*="串文"]',
    '[contenteditable="true"][aria-label*="thread"]',
    '[data-lexical-editor="true"]',
    'div[role="textbox"]',
    '[contenteditable="true"]',
    "textarea",
  ];

  for (const selector of selectors) {
    const locator = page.locator(selector);
    const count = await locator.count();
    for (let i = 0; i < count; i++) {
      const candidate = locator.nth(i);
      if (await isUsableEditor(candidate)) {
        return candidate;
      }
    }
  }

  for (const pattern of COMPOSE_PLACEHOLDERS) {
    const byPlaceholder = page.getByPlaceholder(pattern).first();
    if (await byPlaceholder.isVisible({ timeout: 400 }).catch(() => false)) {
      return byPlaceholder;
    }
  }

  const textboxes = await page.getByRole("textbox").all();
  for (const textbox of textboxes) {
    if (!(await textbox.isVisible().catch(() => false))) continue;
    const editable = await textbox.getAttribute("contenteditable");
    const aria = (await textbox.getAttribute("aria-label")) ?? "";
    const placeholder = (await textbox.getAttribute("placeholder")) ?? "";
    if (
      editable === "true" ||
      /文字|text|串文|貼文|compose|thread/i.test(aria + placeholder)
    ) {
      return textbox;
    }
  }

  const found = await page.evaluate(() => {
    const nodes = Array.from(document.querySelectorAll('[contenteditable="true"], [role="textbox"]'));
    for (const node of nodes) {
      if (!(node instanceof HTMLElement)) continue;
      const rect = node.getBoundingClientRect();
      if (rect.width < 80 || rect.height < 20) continue;
      const style = window.getComputedStyle(node);
      if (style.visibility === "hidden" || style.display === "none") continue;
      node.setAttribute("data-threadtools-editor", "true");
      return true;
    }
    return false;
  });

  if (found) {
    const marked = page.locator('[data-threadtools-editor="true"]').first();
    if (await marked.count()) return marked;
  }

  return null;
}

async function isUsableEditor(candidate: Locator): Promise<boolean> {
  if (!(await candidate.isVisible({ timeout: 400 }).catch(() => false))) return false;
  const box = await candidate.boundingBox().catch(() => null);
  if (!box || box.width < 60 || box.height < 16) return false;
  return true;
}

export async function probeComposeEditor(page: Page, debug?: DebugRun | null): Promise<ComposeReadyResult> {
  const result = await openComposeSurface(page, debug);
  if (!result.ready) return result;

  const editor = await findComposeEditor(page, debug, 8000);
  if (!editor) {
    return {
      ready: false,
      reason: "editor_not_found",
      message: composeFailureMessage("editor_not_found"),
    };
  }

  await dismissBlockingDialogs(page, debug);
  return { ready: true };
}

export function composeFailureMessage(reason?: ComposeBlockReason): string {
  switch (reason) {
    case "instagram_reauth":
      return "Threads 需要完成 Instagram 授權。請到設定頁重新登入，並在彈出的瀏覽器完成 Instagram 登入。";
    case "login_redirect":
      return "Session 已失效，請到設定頁重新登入";
    case "onboarding_dialog":
      return "Threads 有未完成設定的彈窗擋住發文，請重新登入並完成設定";
    case "editor_not_found":
    default:
      return "找不到撰寫欄位。請開啟 Debug 模式查看瀏覽器，或到設定頁重新登入並完成 Instagram 授權。";
  }
}