import { loadImage, sleep } from "../utils.js";
import { MESSAGE_TYPES } from "../../shared/message-types.js";

const CONTENT_SCRIPT_FILES = ["content.bundle.js"];

export async function getActivePageInfo() {
  let tabs = await chrome.tabs.query({ active: true, currentWindow: true });
  let tab = tabs.find((item) => isLikelyBrowserTab(item));

  if (!tab) {
    tabs = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
    tab = tabs.find((item) => isLikelyBrowserTab(item));
  }

  if (!tab) {
    tabs = await chrome.tabs.query({ active: true });
    tab = tabs.find((item) => isLikelyBrowserTab(item));
  }

  return {
    id: tab?.id || 0,
    windowId: tab?.windowId || chrome.windows.WINDOW_ID_CURRENT,
    url: tab?.url || "",
    title: tab?.title || ""
  };
}

export async function captureContextFromActiveTab(includeScreenshot, screenshotMode) {
  const tab = await getActivePageInfo();
  if (!tab.id) {
    throw new Error("No active web page found.");
  }

  await ensureContentScriptReady(tab.id);
  const contextResponse = await chrome.tabs.sendMessage(tab.id, {
    type: MESSAGE_TYPES.CAPTURE_CONTEXT
  });

  if (!contextResponse?.ok) {
    throw new Error(contextResponse?.error || "Failed to capture page context.");
  }

  let screenshotDataUrl = "";
  if (includeScreenshot) {
    screenshotDataUrl =
      screenshotMode === "fullpage"
        ? await captureFullPageScreenshot(tab.id, tab.windowId)
        : await chrome.tabs.captureVisibleTab(tab.windowId, { format: "png" });
  }

  return {
    ...contextResponse.context,
    screenshotDataUrl,
    screenshotMeta: screenshotDataUrl
      ? {
          format: "png",
          source: screenshotMode === "fullpage" ? "fullpage" : "captureVisibleTab"
        }
      : null
  };
}

function isLikelyBrowserTab(tab) {
  const url = String(tab?.url || "");
  return url.startsWith("http://") || url.startsWith("https://");
}

async function captureFullPageScreenshot(tabId, windowId) {
  const infoResponse = await chrome.tabs.sendMessage(tabId, {
    type: MESSAGE_TYPES.GET_CAPTURE_PAGE_INFO
  });
  if (!infoResponse?.ok) {
    throw new Error(infoResponse?.error || "Failed to get page capture info.");
  }

  const info = infoResponse.info;
  const dpr = info.devicePixelRatio || 1;
  const viewportHeight = info.viewportHeight || 1;
  const viewportWidth = info.viewportWidth || 1;
  const fullHeight = info.fullHeight || viewportHeight;
  const fullWidth = info.fullWidth || viewportWidth;

  const canvas = document.createElement("canvas");
  canvas.width = Math.round(fullWidth * dpr);
  canvas.height = Math.round(fullHeight * dpr);
  const ctx = canvas.getContext("2d");
  if (!ctx) {
    throw new Error("Failed to create canvas for full-page screenshot.");
  }

  const originalY = info.scrollY || 0;
  const originalX = info.scrollX || 0;
  const segments = Math.ceil(fullHeight / viewportHeight);

  try {
    for (let index = 0; index < segments; index += 1) {
      const y = Math.min(index * viewportHeight, Math.max(fullHeight - viewportHeight, 0));
      await chrome.tabs.sendMessage(tabId, {
        type: MESSAGE_TYPES.SCROLL_TO,
        payload: { x: 0, y }
      });
      await sleep(250);

      const shot = await chrome.tabs.captureVisibleTab(windowId, { format: "png" });
      const image = await loadImage(shot);
      ctx.drawImage(
        image,
        0,
        0,
        image.width,
        image.height,
        0,
        Math.round(y * dpr),
        Math.round(viewportWidth * dpr),
        Math.round(Math.min(viewportHeight, fullHeight - y) * dpr)
      );
    }

    return canvas.toDataURL("image/png");
  } finally {
    await chrome.tabs.sendMessage(tabId, {
      type: MESSAGE_TYPES.SCROLL_TO,
      payload: { x: originalX, y: originalY }
    });
    await sleep(100);
  }
}

async function ensureContentScriptReady(tabId) {
  try {
    const response = await chrome.tabs.sendMessage(tabId, { type: MESSAGE_TYPES.PING });
    if (response?.ok) {
      return;
    }
  } catch (error) {
    if (!isMissingReceiverError(error)) {
      throw new Error(describeContentScriptInjectionError(error));
    }
  }

  try {
    await chrome.scripting.executeScript({
      target: { tabId },
      files: CONTENT_SCRIPT_FILES
    });
  } catch (error) {
    throw new Error(describeContentScriptInjectionError(error));
  }
}

function isMissingReceiverError(error) {
  return /Receiving end does not exist|Could not establish connection/i.test(String(error?.message || error || ""));
}

function describeContentScriptInjectionError(error) {
  const text = String(error?.message || error || "");
  if (/Cannot access contents of url/i.test(text)) {
    return "当前页面不允许读取内容，例如浏览器内部页或受限页面。";
  }
  return text || "无法在当前页面注入内容脚本。";
}
