importScripts("taskModule.js");

let pageState = { inData: {}, pageName: "home", llmname: "" };
let sidebarOpen = false;
let webcontent = {};

// Request latest page info from a tab and broadcast to the sidebar.
// "options.loading" lets callers explicitly set the loading flag so that
// subsequent content-script responses do not wipe it out.
// "options.seed" provides a minimal starting payload (e.g., url) so we can
// avoid leaking stale page data while a new navigation is in-flight.
async function refreshWebcontent(tabId, options = {}) {
  if (tabId === undefined || tabId === null) return;

  const loadingOverride = options.loading;
  const seed = options.seed || {};
  const currentLoading = loadingOverride !== undefined ? loadingOverride : (webcontent?.loading ?? false);
  const snapshot = { ...(webcontent || {}), ...seed, loading: currentLoading };

  chrome.runtime.sendMessage({ type: "CHANGE_WEB", webcontent: snapshot }, () => {
    void chrome.runtime.lastError;
  });

  return new Promise((resolve) => {
    chrome.tabs.sendMessage(tabId, { type: "READ_WEB" }, (responseFromContent) => {
      const err = chrome.runtime.lastError;
      if (err) {
        // Swallow "receiving end does not exist" when no content script is injected on the tab.
        resolve(snapshot);
        return;
      }

      if (!responseFromContent || !responseFromContent.webcontent) {
        // If the tab is an http(s) page but the content script hasn't responded yet, keep the UI in loading.
        chrome.tabs.get(tabId, (tab) => {
          if (tab?.url?.startsWith("http")) {
            chrome.runtime.sendMessage({ type: "CHANGE_WEB", webcontent: snapshot }, () => {
              void chrome.runtime.lastError;
            });
            resolve(snapshot);
          } else {
            const cleared = { url: tab?.url, loading: false };
            webcontent = cleared;
            chrome.runtime.sendMessage({ type: "CHANGE_WEB", webcontent: cleared }, () => {
              void chrome.runtime.lastError;
            });
            resolve(cleared);
          }
        });
        return;
      }

      const merged = { ...responseFromContent.webcontent, loading: currentLoading };
      webcontent = merged;
      chrome.runtime.sendMessage({ type: "CHANGE_WEB", webcontent: merged }, () => {
        void chrome.runtime.lastError;
      });
      resolve(merged);
    });
  });
}

TaskModule.init();
// Helpers to persist pageState so selections (like `llmname`) survive restarts
async function loadPageStateFromStorage() {
  return new Promise((resolve) => {
    try {
      chrome.storage.local.get(["pageState"], (res) => {
        resolve(res?.pageState || null);
      });
    } catch {
      resolve(null);
    }
  });
}

function savePageStateToStorage(state) {
  try {
    chrome.storage.local.set({ pageState: state }, () => {
      void chrome.runtime.lastError;
    });
  } catch {}
}

// Load any previously saved pageState (keeps last selected `llmname`)
(async () => {
  try {
    const saved = await loadPageStateFromStorage();
    if (saved && typeof saved === "object") {
      pageState = { ...pageState, ...saved };
    }
  } catch {}
})();
// Debug: confirm SW starts when woken by any event
console.log("BlackEagle background service worker initialized");

// ===== Browser Extension install/startup reporting =====
const SERVER_BASE_DEFAULT = "https://api.cozyai.chat"; // adjust if needed

async function getServerBase() {
  return new Promise((resolve) => {
    try {
      chrome.storage.local.get(["serverBase"], (res) => {
        resolve(res?.serverBase || SERVER_BASE_DEFAULT);
      });
    } catch {
      resolve(SERVER_BASE_DEFAULT);
    }
  });
}

async function getDeviceId() {
  return new Promise((resolve) => {
    try {
      chrome.storage.local.get(["deviceId"], (res) => {
        let id = res?.deviceId;
        if (id && typeof id === "string" && id.length > 0) {
          resolve(id);
          return;
        }
        id = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
        chrome.storage.local.set({ deviceId: id }, () => {
          void chrome.runtime.lastError;
          resolve(id);
        });
      });
    } catch {
      resolve(`${Date.now()}-${Math.random().toString(36).slice(2, 10)}`);
    }
  });
}

function getBrowserInfo() {
  const ua = (globalThis?.navigator?.userAgent || "").toLowerCase();
  let browser = "Chrome";
  if (ua.includes("edg/")) browser = "Edge";
  else if (ua.includes("firefox")) browser = "Firefox";
  else if (ua.includes("safari") && !ua.includes("chrome")) browser = "Safari";

  const platform = globalThis?.navigator?.platform || globalThis?.navigator?.userAgentData?.platform || "";
  return { browser, platform };
}

async function reportEvent(event) {
  try {
    const serverBase = await getServerBase();
    const deviceId = await getDeviceId();
    const { browser, platform } = getBrowserInfo();
    const version = chrome.runtime.getManifest()?.version || "";
    const payload = {
      ext: "blackeagle",
      event,
      version,
      browser,
      platform,
      deviceId,
      extra: event === "install" ? { source: "ChromeWebStore" } : undefined,
    };

    await fetch(`${serverBase}/app/browserex`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
    });
  } catch (e) {
    // swallow network errors to avoid disrupting extension
  }
}

chrome.runtime.onInstalled.addListener(async (details) => {
  try {
    const reason = details?.reason || "unknown";
    // console.log(`onInstalled: reason=${reason}`);
    if (reason === "install") {
      await reportEvent("install");
    } else if (reason === "update") {
      await reportEvent("update");
    } else if (reason === "chrome_update") {
      await reportEvent("chrome_update");
    }
  } catch (e) {
    // ignore
  }
});

chrome.runtime.onStartup.addListener(async () => {
  await reportEvent("startup");
});

chrome.action.onClicked.addListener(async (tab) => {
  chrome.sidePanel.setOptions(
    {
      path: "sidebar.html",
      tabId: tab.id,
    },
    () => {
      chrome.sidePanel.open({ tabId: tab.id });
      sidebarOpen = true;
      refreshWebcontent(tab.id);
    },
  );
});

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  const nextUrl = changeInfo.url || tab?.url || webcontent?.url;

  // If URL changes (including History API in some cases), treat as a new page load
  if (changeInfo.url) {
    webcontent = { url: nextUrl, loading: true };
    refreshWebcontent(tabId, { loading: true, seed: { url: nextUrl } });
    return;
  }

  if (changeInfo.status === "loading") {
    webcontent = { url: nextUrl, loading: true };
    refreshWebcontent(tabId, { loading: true, seed: { url: nextUrl } });
    return;
  }

  if (changeInfo.status === "complete") {
    webcontent = { ...(webcontent || {}), url: nextUrl, loading: false };
    refreshWebcontent(tabId, { loading: false, seed: { url: nextUrl } });
  }
});

chrome.tabs.onActivated.addListener(async (activeInfo) => {
  try {
    refreshWebcontent(activeInfo.tabId);
  } catch (error) {
    console.error("Error getting active tab:", error);
  }
});

async function focusOrCreateTargetTab(url) {
  // 查询当前所有标签页
  const tabs = await chrome.tabs.query({});

  // 遍历查找是否有包含目标域名的标签页
  for (const tab of tabs) {
    if (tab.url && (tab.url.includes(url) || (url.includes("xiaozhi") && tab.url.includes("xiaozhi")))) {
      // 激活该标签页并切换到所在窗口
      await chrome.tabs.update(tab.id, { active: true, url });
      // await chrome.windows.update(tab.windowId, { focused: true });
      // await chrome.tabs.reload(tab.id);
      return;
    }
  }
  // 如果没有则新建一个
  await chrome.tabs.create({ url });
}

chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (TaskModule.handleMessage(msg, sendResponse)) {
    return true; // keep channel open for async responses
  }
  // Schedule reminder via alarms + notifications
  if (msg.type === "SCHEDULE_REMINDER") {
    try {
      const payload = msg.payload || {};
      const id = String(payload.id || `reminder_${Date.now()}`);
      const title = String(payload.title || "").trim();
      const message = String(payload.message || "").trim();
      const targetTs = Number(payload.targetTs);
      const periodInMinutes = Number(payload.periodInMinutes);

      if (!title || !message || !Number.isFinite(targetTs)) {
        sendResponse({ success: false, error: "INVALID_PAYLOAD" });
        return true;
      }

      const when = Math.max(Date.now(), targetTs);
      if (Number.isFinite(periodInMinutes) && periodInMinutes > 0) {
        chrome.alarms.create(id, { when, periodInMinutes });
      } else {
        chrome.alarms.create(id, { when });
      }

      // Persist reminder info so service worker can retrieve on alarm
      chrome.storage.local.get(["scheduledReminders"], (res) => {
        const map = res?.scheduledReminders || {};
        map[id] = { title, message, when, periodInMinutes: Number.isFinite(periodInMinutes) ? periodInMinutes : undefined };
        chrome.storage.local.set({ scheduledReminders: map }, () => {
          void chrome.runtime.lastError;
          sendResponse({ success: true, id, when });
        });
      });
    } catch (e) {
      sendResponse({ success: false, error: (e && e.message) || "SCHEDULE_FAILED" });
    }
    return true; // async
  }
  if (msg.type === "CANCEL_REMINDER") {
    try {
      const id = String(msg?.payload?.id || "").trim();
      if (!id) {
        sendResponse({ success: false, error: "INVALID_ID" });
        return true;
      }

      chrome.alarms.clear(id, () => {
        void chrome.runtime.lastError;
      });

      chrome.storage.local.get(["scheduledReminders"], (res) => {
        const map = res?.scheduledReminders || {};
        if (map[id]) {
          delete map[id];
          chrome.storage.local.set({ scheduledReminders: map }, () => {
            void chrome.runtime.lastError;
            sendResponse({ success: true, id });
          });
        } else {
          sendResponse({ success: true, id, note: "not_found" });
        }
      });
    } catch (e) {
      sendResponse({ success: false, error: (e && e.message) || "CANCEL_FAILED" });
    }
    return true;
  }
  if (msg.type === "CHECK_ACTIVE_TAB") {
    //监测当前活动标签页
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      const activeTabId = tabs[0]?.id;
      const isActive = sender.tab?.id === activeTabId;
      sendResponse({ isActive });
    });
  }
  if (msg.type === "CANCEL_ALL_REMINDERS") {
    try {
      chrome.alarms.clearAll(() => {
        void chrome.runtime.lastError;
      });
      chrome.storage.local.set({ scheduledReminders: {} }, () => {
        void chrome.runtime.lastError;
        sendResponse({ success: true });
      });
    } catch (e) {
      sendResponse({ success: false, error: (e && e.message) || "CANCEL_ALL_FAILED" });
    }
    return true;
  }
  if (msg.type === "OPEN_AGENTTALK_PANEL") {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      const tabId = tabs?.[0]?.id;
      if (!tabId) {
        sendResponse({ success: false });
        return;
      }
      chrome.sidePanel
        .open({ tabId })
        .then(() => sendResponse({ success: true }))
        .catch(() => sendResponse({ success: false }));
    });
    return true;
  }
  if (msg.type === "REQUEST_WEBCONTENT") {
    try {
      chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
        try {
          const tabId = tabs?.[0]?.id;
          if (tabId === undefined) {
            sendResponse({ success: false, error: "NO_ACTIVE_TAB", webcontent });
            return;
          }
          const refreshed = await refreshWebcontent(tabId);
          sendResponse({ success: true, webcontent: refreshed || webcontent });
        } catch (err) {
          sendResponse({ success: false, error: (err && err.message) || "REFRESH_FAILED", webcontent });
        }
      });
    } catch (e) {
      sendResponse({ success: false, error: (e && e.message) || "REQUEST_WEBCONTENT_FAILED", webcontent });
    }
    return true;
  }
  if (msg.type === "CHANGE_WEB") {
    //切换web
    const incoming = msg.webcontent || {};
    const incomingLoading = incoming.loading;
    const nextLoading = incomingLoading !== undefined ? incomingLoading : webcontent?.loading;
    webcontent = { ...incoming, loading: nextLoading }; // preserve current loading flag unless sender sets it explicitly
    chrome.runtime.sendMessage({ type: "CHANGE_WEB", webcontent: webcontent }, () => {
      void chrome.runtime.lastError;
    });
    sendResponse({ success: true });
  }
  if (msg.type === "SELECTED_TEXT") {
    //选中文本
    chrome.runtime.sendMessage({ type: "SELECTED_TEXT", text: msg.text }, () => {
      void chrome.runtime.lastError;
    });
    sendResponse({ success: true });
  }
  if (msg.type === "OPEN_URL") {
    //打开新标签页
    focusOrCreateTargetTab(msg.payload.url);
    sendResponse({ success: true });
  }
  if (msg.type === "XIAOZHI_TOKEN") {
    //得到登录授权
    chrome.runtime.sendMessage({ type: "TOKEN_READY", token: msg.token }, () => {
      void chrome.runtime.lastError;
    });
    sendResponse({ success: true });
  } else if (msg.type === "SAVE_PAGE_STATE") {
    // 保存页面状态
    pageState = { ...pageState, ...msg.payload };
    try {
      savePageStateToStorage(pageState);
    } catch {}
    sendResponse({ success: true });
  } else if (msg.type === "GET_PAGE_STATE") {
    // 获取当前页面装填
    sendResponse({ payload: pageState });
  } else {
    //转发其它所有插件请求
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      tabs.forEach((tab) => {
        if (tab.id !== undefined) {
          chrome.tabs.sendMessage(tab.id, { type: msg.type, payload: msg.payload }, (responseFromContent) => {
            if (chrome.runtime.lastError) {
              sendResponse({ success: false, error: chrome.runtime.lastError.message });
              return;
            }
            // console.log(msg.type + ":::" + responseFromContent);
            sendResponse(responseFromContent ?? { success: false, error: "NO_RESPONSE" });
          });
        }
      });
    });
  }
  return true;
});

// Alarm listener: show notification and cleanup
chrome.alarms.onAlarm.addListener((alarm) => {
  try {
    const id = alarm?.name || "";
    chrome.storage.local.get(["scheduledReminders"], (res) => {
      const map = res?.scheduledReminders || {};
      const info = map[id];
      if (!info) return;

      const { title, message } = info;
      try {
        chrome.notifications.create(id, {
          type: "basic",
          iconUrl: "icons/icon128.png",
          title: title || "提醒",
          message: message || "",
        });
      } catch (e) {
        // swallow
      }

      // Update next fire time for recurring; otherwise cleanup
      try {
        const period = Number(info?.periodInMinutes);
        if (Number.isFinite(period) && period > 0) {
          const nextWhen = Date.now() + period * 60_000;
          map[id] = { ...info, when: nextWhen };
        } else {
          delete map[id];
        }
        chrome.storage.local.set({ scheduledReminders: map }, () => {
          void chrome.runtime.lastError;
        });
      } catch {}
    });
  } catch (e) {
    // ignore
  }
});

// When a reminder notification is clicked, focus browser and open side panel
chrome.notifications.onClicked.addListener((notificationId) => {
  try {
    chrome.notifications.clear(notificationId, () => {
      void chrome.runtime.lastError;
    });

    // Focus the last focused window, then open side panel on its active tab
    chrome.windows.getLastFocused({ populate: false }, (win) => {
      if (win?.id !== undefined) {
        chrome.windows.update(win.id, { focused: true }, () => {
          void chrome.runtime.lastError;
          chrome.tabs.query({ active: true, windowId: win.id }, (tabs) => {
            const tabId = tabs?.[0]?.id;
            if (!tabId) return;
            chrome.sidePanel
              .open({ tabId })
              .then(() => {
                chrome.sidePanel.setOptions({ path: "sidebar.html", tabId }, () => {
                  void chrome.runtime.lastError;
                });
              })
              .catch(() => {
                // ignore
              });
          });
        });
      }
    });
  } catch (e) {
    // ignore
  }
});
