import { buildStorageState } from "./storage-state.js";

const CONTENT_SCRIPT_ID = "haixun-bridge";
const GO_API_SUCCESS_CODE = 102000;
const DEV_WEB_PORTS = new Set(["3000", "4173", "5173"]);

function unwrapGoApiResponse(raw) {
  if (raw && typeof raw === "object" && "code" in raw) {
    if (raw.code !== GO_API_SUCCESS_CODE) {
      throw new Error(raw.message || `API error ${raw.code}`);
    }
    return raw.data && typeof raw.data === "object" ? raw.data : {};
  }
  return raw && typeof raw === "object" ? raw : {};
}

function parseApiError(raw, status) {
  if (raw && typeof raw === "object") {
    if (typeof raw.message === "string" && raw.message.trim()) return raw.message;
    if (typeof raw.error === "string" && raw.error.trim()) return raw.error;
  }
  return `匯入失敗（HTTP ${status}）`;
}

function equivalentOrigins(origin) {
  const url = new URL(origin);
  const port = url.port ? `:${url.port}` : "";
  const origins = new Set([url.origin]);
  if (url.hostname === "localhost") {
    origins.add(`${url.protocol}//127.0.0.1${port}`);
  } else if (url.hostname === "127.0.0.1") {
    origins.add(`${url.protocol}//localhost${port}`);
  }
  return [...origins];
}

function resolveApiBase(serverUrl) {
  const url = new URL(serverUrl);
  if (DEV_WEB_PORTS.has(url.port)) {
    // Prefer 127.0.0.1 to match backend default bind address.
    const host = url.hostname === "localhost" ? "127.0.0.1" : url.hostname;
    return `${url.protocol}//${host}:8890`;
  }
  return url.origin;
}

async function requestHostPermission(serverOrigin) {
  const origins = equivalentOrigins(serverOrigin).map((item) => `${item}/*`);
  const granted = await chrome.permissions.contains({ origins });
  if (granted) return true;
  return chrome.permissions.request({ origins });
}

async function queryHaixunTabs(serverOrigin) {
  const tabsById = new Map();
  for (const origin of equivalentOrigins(serverOrigin)) {
    const tabs = await chrome.tabs.query({ url: `${origin}/*` });
    for (const tab of tabs) {
      if (tab.id != null) tabsById.set(tab.id, tab);
    }
  }
  return [...tabsById.values()];
}

async function ensureContentScript(serverOrigin) {
  const patterns = equivalentOrigins(serverOrigin).map((item) => `${item}/*`);
  const existing = await chrome.scripting.getRegisteredContentScripts();
  if (existing.some((script) => script.id === CONTENT_SCRIPT_ID)) {
    return;
  }

  await chrome.scripting.registerContentScripts([
    {
      id: CONTENT_SCRIPT_ID,
      matches: patterns,
      js: ["content-haixun.js"],
      runAt: "document_start",
    },
  ]);
}

async function injectBridgeIntoTabs(serverOrigin) {
  const tabs = await queryHaixunTabs(serverOrigin);
  for (const tab of tabs) {
    if (!tab.id) continue;
    try {
      await chrome.scripting.executeScript({
        target: { tabId: tab.id },
        files: ["content-haixun.js"],
      });
    } catch {
      // Ignore duplicate injection / restricted pages.
    }
  }
}

async function readAuthFromHaixunTab(serverOrigin) {
  const tabs = await queryHaixunTabs(serverOrigin);
  for (const tab of tabs) {
    if (!tab.id) continue;
    const [result] = await chrome.scripting.executeScript({
      target: { tabId: tab.id },
      func: () => {
        const pathname = location.pathname ?? "";
        const fromPath = pathname.match(/\/threads\/([^/]+)/)?.[1] ?? "";
        return {
          accessToken: localStorage.getItem("haixun.access_token") ?? "",
          accountId:
            fromPath || localStorage.getItem("haixun.active_threads_account_id") || "",
          origin: location.origin,
        };
      },
    });
    const payload = result?.result;
    if (payload?.accessToken) {
      return payload;
    }
  }
  return null;
}

export async function syncThreadsSessionToGo(serverUrl, accountId, accessToken) {
  const origin = new URL(serverUrl).origin;
  const apiBase = resolveApiBase(serverUrl);

  if (!accountId) {
    throw new Error(
      "缺少經營帳號 ID。請在巡樓頂部切換帳號，或開啟 /threads/:id/connections 後再同步"
    );
  }
  if (!accessToken) {
    const hint = equivalentOrigins(origin).join(" 或 ");
    throw new Error(
      `找不到巡樓登入狀態。請在 Chrome 開啟並登入 ${hint}（需為新版巡樓 :5173，不是舊版 :3000）`
    );
  }

  let storageState;
  try {
    storageState = await buildStorageState();
  } catch (error) {
    throw error;
  }

  let res;
  try {
    res = await fetch(
      `${apiBase}/api/v1/threads-accounts/${encodeURIComponent(accountId)}/session/import`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${accessToken}`,
        },
        body: JSON.stringify({ storageState }),
      }
    );
  } catch (error) {
    const msg = error instanceof Error ? error.message : String(error);
    if (/fetch|network|failed/i.test(msg)) {
      throw new Error(
        `無法連線後端 ${apiBase}。請確認已執行 make run（或 backend:8d），且 :8890 有在跑`
      );
    }
    throw error;
  }

  const raw = await res.json().catch(() => ({}));
  if (!res.ok) {
    throw new Error(parseApiError(raw, res.status));
  }

  const data = unwrapGoApiResponse(raw);
  if (data.valid === false) {
    throw new Error(data.message || "Session 驗證失敗");
  }
  return data;
}

async function resolveServerUrl(partial) {
  if (partial) return new URL(partial).origin;

  const stored = await chrome.storage.sync.get(["serverUrl"]);
  if (stored.serverUrl) return new URL(stored.serverUrl).origin;

  const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
  const activeUrl = tabs[0]?.url;
  if (activeUrl) {
    try {
      const origin = new URL(activeUrl).origin;
      const port = new URL(activeUrl).port;
      if (DEV_WEB_PORTS.has(port) || activeUrl.includes("/threads/")) {
        return origin;
      }
    } catch {
      // ignore
    }
  }

  throw new Error("請在擴充功能選項設定巡樓網址（例如 http://localhost:5173），或先開啟巡樓分頁");
}

chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
  if (message?.action !== "sync") return undefined;

  (async () => {
    try {
      const serverUrl = await resolveServerUrl(message.serverUrl);
      const allowed = await requestHostPermission(serverUrl);
      if (!allowed) {
        throw new Error("需要授權存取巡樓網站才能同步");
      }

      await ensureContentScript(serverUrl);
      await injectBridgeIntoTabs(serverUrl);

      let accountId = message.accountId ?? "";
      let accessToken = message.accessToken ?? "";
      if (!accountId || !accessToken) {
        const auth = await readAuthFromHaixunTab(serverUrl);
        if (auth) {
          accountId = accountId || auth.accountId;
          accessToken = accessToken || auth.accessToken;
        }
      }

      const result = await syncThreadsSessionToGo(serverUrl, accountId, accessToken);
      sendResponse({
        success: true,
        valid: result.valid !== false,
        synced: result.synced ?? true,
        account_id: result.account_id ?? result.accountId,
        username: result.username,
        message: result.message || "Chrome session 已同步",
      });
    } catch (error) {
      sendResponse({
        success: false,
        valid: false,
        message: error instanceof Error ? error.message : "同步失敗",
      });
    }
  })();

  return true;
});

chrome.runtime.onInstalled.addListener(async () => {
  const { serverUrl } = await chrome.storage.sync.get(["serverUrl"]);
  if (!serverUrl) {
    await chrome.storage.sync.set({ serverUrl: "http://localhost:5173" });
  }
});