"use strict"; (() => { // src/popup/view.ts function renderLoggedOut(root, error) { root.innerHTML = `

Star Chart Search Enhancer

\u767B\u5F55\u540E\u624D\u80FD\u4F7F\u7528\u661F\u56FE\u589E\u5F3A\u529F\u80FD

${error ? `

${error}

` : ""}
`; } function renderLoggedIn(root, authState) { const userInfo = authState.userInfo; root.innerHTML = `

Star Chart Search Enhancer

\u5DF2\u767B\u5F55

${userInfo?.name ?? userInfo?.username ?? "\u672A\u77E5\u7528\u6237"}

${userInfo?.email ?? ""}

\u7248\u672C\u66F4\u65B0

\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...

`; } function renderUpdateStatus(root, options) { const container = root.querySelector('[data-popup-update="root"]'); if (!container) { return; } if (options.status === "checking") { container.innerHTML = `

\u7248\u672C\u66F4\u65B0

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

\u6B63\u5728\u68C0\u67E5\u66F4\u65B0...

`; return; } if (options.status === "error") { container.innerHTML = `

\u7248\u672C\u66F4\u65B0

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

\u6682\u65F6\u65E0\u6CD5\u68C0\u67E5\u66F4\u65B0

\u5982\u679C\u9700\u8981\u65B0\u7248\uFF0C\u8BF7\u8054\u7CFB\u7EF4\u62A4\u540C\u4E8B\u83B7\u53D6\u66F4\u65B0\u5305\u3002

`; return; } if (options.status === "latest" || !options.manifest) { container.innerHTML = `

\u7248\u672C\u66F4\u65B0

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C

`; return; } container.innerHTML = `

\u7248\u672C\u66F4\u65B0

\u5F53\u524D\u7248\u672C\uFF1A${options.currentVersion}

\u53D1\u73B0\u65B0\u7248\u672C\uFF1A${options.manifest.latestVersion}

${renderReleaseNotes(options.manifest.releaseNotes)}

\u4E0B\u8F7D\u540E\u8BF7\u89E3\u538B\u65B0\u7248 zip\uFF0C\u5E76\u5728 chrome://extensions \u91CC\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002

`; } function setUpdateDownloadStatus(root, value) { const output = root.querySelector('[data-popup-update-download-status="text"]'); if (!output) { return; } output.textContent = value; } function renderReleaseNotes(releaseNotes) { if (releaseNotes.length === 0) { return ""; } return ` `; } function escapeHtml(value) { return value.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function renderDevPanel(root, authState) { const panel = root.ownerDocument.createElement("section"); panel.dataset.popupDevPanel = "root"; panel.innerHTML = `

dev auth panel

resource: ${authState.resource ?? ""}

scopes: ${(authState.scopes ?? []).join(", ")}

token: ${authState.tokenAvailable ? "available" : "missing"}

expires: ${authState.accessTokenExpiresAt ?? "unknown"}

error: ${authState.lastError ?? ""}


  `;
    root.appendChild(panel);
  }
  function setProtectedApiResult(root, value) {
    const output = root.querySelector(
      '[data-popup-protected-api-result="output"]'
    );
    if (!output) {
      return;
    }
    output.textContent = value;
  }

  // src/shared/auth-config.ts
  var defaultAuthConfig = {
    apiResource: "https://talent-search.intelligrow.cn",
    appId: "i4jkllbvih0554r4n0fd3",
    enableDevAuthPanel: false,
    logtoEndpoint: "https://login-api.intelligrow.cn",
    scopes: ["openid", "profile", "offline_access", "talent-search:read"]
  };
  function readAuthConfig(overrides = {}) {
    const nextConfig = {
      ...defaultAuthConfig,
      ...overrides
    };
    if (!nextConfig.logtoEndpoint.trim()) {
      throw new Error("auth config logtoEndpoint is required");
    }
    if (!nextConfig.appId.trim()) {
      throw new Error("auth config appId is required");
    }
    if (!nextConfig.apiResource.trim()) {
      throw new Error("auth config apiResource is required");
    }
    return nextConfig;
  }

  // src/shared/auth-messages.ts
  function isAuthResponseMessage(value) {
    if (!value || typeof value !== "object") {
      return false;
    }
    const candidate = value;
    if (candidate.ok === false) {
      return candidate.type === "auth:error" && typeof candidate.error === "string";
    }
    if (candidate.ok !== true || typeof candidate.type !== "string") {
      return false;
    }
    if (candidate.type === "auth:ack") {
      return true;
    }
    if (candidate.type === "auth:token") {
      return Boolean(
        candidate.value && typeof candidate.value === "object" && typeof candidate.value.accessToken === "string"
      );
    }
    if (candidate.type === "auth:state") {
      return Boolean(
        candidate.value && typeof candidate.value === "object" && typeof candidate.value.isAuthenticated === "boolean"
      );
    }
    return false;
  }

  // src/shared/protected-api-client.ts
  function createProtectedApiClient(options) {
    const fetchImpl = options.fetchImpl ?? fetch;
    return {
      async loadProtectedMockData() {
        const token = await readAccessToken(options.sendMessage);
        const response = await fetchImpl(
          new URL("/api/mock/protected", options.baseUrl).toString(),
          {
            headers: {
              Authorization: `Bearer ${token}`
            },
            method: "GET"
          }
        );
        if (response.status === 401 || response.status === 403) {
          throw new Error("protected api unauthorized");
        }
        if (!response.ok) {
          throw new Error(`protected api request failed: ${response.status}`);
        }
        return response.json();
      }
    };
  }
  async function readAccessToken(sendMessage) {
    const response = await sendMessage({ type: "auth:get-access-token" });
    if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:token" || !response.value.accessToken.trim()) {
      throw new Error("protected api token unavailable");
    }
    return response.value.accessToken;
  }

  // src/shared/update-check.ts
  function compareExtensionVersions(left, right) {
    const leftParts = parseVersionParts(left);
    const rightParts = parseVersionParts(right);
    const maxLength = Math.max(leftParts.length, rightParts.length);
    for (let index = 0; index < maxLength; index += 1) {
      const leftValue = leftParts[index] ?? 0;
      const rightValue = rightParts[index] ?? 0;
      if (leftValue !== rightValue) {
        return leftValue - rightValue;
      }
    }
    return 0;
  }
  function parseUpdateManifest(value) {
    if (!value || typeof value !== "object") {
      return null;
    }
    const candidate = value;
    if (!isVersionString(candidate.latestVersion) || !isVersionString(candidate.minSupportedVersion) || !isHttpsUrl(candidate.zipUrl) || !isHttpsUrl(candidate.guideUrl) || typeof candidate.publishedAt !== "string" || !Array.isArray(candidate.releaseNotes) || !candidate.releaseNotes.every((note) => typeof note === "string")) {
      return null;
    }
    return {
      guideUrl: candidate.guideUrl,
      latestVersion: candidate.latestVersion,
      minSupportedVersion: candidate.minSupportedVersion,
      publishedAt: candidate.publishedAt,
      releaseNotes: candidate.releaseNotes,
      zipUrl: candidate.zipUrl
    };
  }
  async function fetchUpdateManifest(manifestUrl, fetchImpl = fetch) {
    const response = await fetchImpl(manifestUrl, {
      cache: "no-store"
    });
    if (!response.ok) {
      throw new Error(`update manifest request failed: ${response.status}`);
    }
    const manifest = parseUpdateManifest(await response.json());
    if (!manifest) {
      throw new Error("update manifest is invalid");
    }
    return manifest;
  }
  function parseVersionParts(value) {
    return value.split(".").map((part) => {
      const parsed = Number.parseInt(part, 10);
      return Number.isFinite(parsed) ? parsed : 0;
    });
  }
  function isVersionString(value) {
    return typeof value === "string" && /^\d+(?:\.\d+)*$/.test(value);
  }
  function isHttpsUrl(value) {
    if (typeof value !== "string") {
      return false;
    }
    try {
      return new URL(value).protocol === "https:";
    } catch {
      return false;
    }
  }

  // src/shared/update-config.ts
  var UPDATE_MANIFEST_URL = "https://wksgx-1343191620.cos.ap-nanjing.myqcloud.com/star-chart-search-enhancer/latest.json";

  // src/popup/index.ts
  async function bootPopup(options = {}) {
    const currentDocument = options.document ?? document;
    const popupConfig = readAuthConfig(options.config);
    const currentVersion = options.currentVersion ?? readCurrentVersion();
    const root = currentDocument.querySelector("#app");
    const HTMLElementCtor = currentDocument.defaultView?.HTMLElement;
    if (!root || HTMLElementCtor && !(root instanceof HTMLElementCtor)) {
      throw new Error("popup root #app is required");
    }
    const sendMessage = options.sendMessage ?? ((message) => Promise.resolve(
      globalThis.chrome?.runtime?.sendMessage?.(message)
    ));
    const fetchProtectedApi = options.fetchProtectedApi ?? createProtectedApiClient({
      baseUrl: "http://127.0.0.1:4319",
      sendMessage
    }).loadProtectedMockData;
    const fetchUpdateManifest2 = options.fetchUpdateManifest ?? (() => fetchUpdateManifest(
      options.updateManifestUrl ?? UPDATE_MANIFEST_URL
    ));
    await renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi, {
      currentVersion,
      fetchUpdateManifest: fetchUpdateManifest2
    });
  }
  async function renderCurrentAuthState(root, popupConfig, sendMessage, fetchProtectedApi, updateOptions) {
    const response = await sendMessage({ type: "auth:get-state" });
    if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:state") {
      renderLoggedOut(root, "\u8BA4\u8BC1\u72B6\u6001\u8BFB\u53D6\u5931\u8D25");
      return;
    }
    if (!response.value.isAuthenticated) {
      renderLoggedOut(root, response.value.lastError);
      root.querySelector('[data-popup-sign-in="button"]')?.addEventListener("click", () => {
        void runAuthAction(root, popupConfig, sendMessage, {
          actionMessage: { type: "auth:sign-in" },
          fetchProtectedApi,
          updateOptions
        });
      });
      return;
    }
    renderLoggedIn(root, response.value);
    void runUpdateCheck(root, sendMessage, updateOptions);
    root.querySelector('[data-popup-sign-out="button"]')?.addEventListener("click", () => {
      void runAuthAction(root, popupConfig, sendMessage, {
        actionMessage: { type: "auth:sign-out" },
        fetchProtectedApi,
        updateOptions
      });
    });
    if (popupConfig.enableDevAuthPanel) {
      renderDevPanel(root, response.value);
      root.querySelector('[data-popup-test-protected-api="button"]')?.addEventListener("click", () => {
        void runProtectedApiProbe(root, fetchProtectedApi);
      });
    }
  }
  async function runAuthAction(root, popupConfig, sendMessage, options) {
    const response = await sendMessage(options.actionMessage);
    if (isActionError(response)) {
      renderLoggedOut(root, response.error);
      root.querySelector('[data-popup-sign-in="button"]')?.addEventListener("click", () => {
        void runAuthAction(root, popupConfig, sendMessage, options);
      });
      return;
    }
    await renderCurrentAuthState(
      root,
      popupConfig,
      sendMessage,
      options.fetchProtectedApi,
      options.updateOptions
    );
  }
  function isActionError(response) {
    return isAuthResponseMessage(response) && !response.ok && response.type === "auth:error";
  }
  async function runUpdateCheck(root, sendMessage, options) {
    renderUpdateStatus(root, {
      currentVersion: options.currentVersion,
      status: "checking"
    });
    try {
      const manifest = await options.fetchUpdateManifest();
      if (compareExtensionVersions(manifest.latestVersion, options.currentVersion) <= 0) {
        renderUpdateStatus(root, {
          currentVersion: options.currentVersion,
          status: "latest"
        });
        return;
      }
      renderUpdateStatus(root, {
        currentVersion: options.currentVersion,
        manifest,
        status: "available"
      });
      bindUpdateDownloadButtons(root, sendMessage, manifest);
    } catch {
      renderUpdateStatus(root, {
        currentVersion: options.currentVersion,
        status: "error"
      });
    }
  }
  function bindUpdateDownloadButtons(root, sendMessage, manifest) {
    root.querySelector('[data-popup-download-update="button"]')?.addEventListener("click", () => {
      void downloadUpdateAsset(root, sendMessage, {
        filename: "star-chart-search-enhancer-internal.zip",
        url: manifest.zipUrl
      });
    });
    root.querySelector('[data-popup-download-guide="button"]')?.addEventListener("click", () => {
      void downloadUpdateAsset(root, sendMessage, {
        filename: "\u661F\u56FE\u589E\u5F3A\u63D2\u4EF6-\u8D85\u7B80\u5355\u5B89\u88C5\u4F7F\u7528\u6307\u5357.pdf",
        url: manifest.guideUrl
      });
    });
  }
  async function downloadUpdateAsset(root, sendMessage, options) {
    setUpdateDownloadStatus(root, "\u6B63\u5728\u4E0B\u8F7D...");
    try {
      await sendMessage({
        filename: options.filename,
        type: "update:download",
        url: options.url
      });
      setUpdateDownloadStatus(root, "\u5DF2\u89E6\u53D1\u4E0B\u8F7D\u3002\u4E0B\u8F7D\u540E\u8BF7\u89E3\u538B\u65B0\u7248 zip\uFF0C\u5E76\u5728 chrome://extensions \u91CC\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u3002");
    } catch (error) {
      setUpdateDownloadStatus(
        root,
        error instanceof Error ? error.message : "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"
      );
    }
  }
  function readCurrentVersion() {
    const runtime = globalThis.chrome?.runtime;
    return runtime?.getManifest?.().version ?? "0.0.0";
  }
  async function runProtectedApiProbe(root, fetchProtectedApi) {
    setProtectedApiResult(root, "\u8BF7\u6C42\u4E2D...");
    try {
      const result = await fetchProtectedApi();
      setProtectedApiResult(root, JSON.stringify(result, null, 2));
    } catch (error) {
      setProtectedApiResult(
        root,
        error instanceof Error ? error.message : String(error)
      );
    }
  }
  if (typeof document !== "undefined") {
    void bootPopup();
  }
})();