"use strict";
(() => {
  // src/lib/config.ts
  var API_BASE_URL = "https://inspectapi.dghq.app";
  var BOT_BASE_URL = "https://inspectbot.dghq.app";
  var BUILT_IN_EXTENSION_KEY = "e1cf4e5f2d49ac54723b3fb18ed13a6970360993032f22d1b46512ac9ab149c2";

  // src/lib/settings.ts
  var DEFAULTS = {
    apiKey: ""
  };
  async function getSettings() {
    const stored = await chrome.storage.local.get(DEFAULTS);
    return stored;
  }
  function getEffectiveApiKey(s) {
    const trimmed = (s.apiKey ?? "").trim();
    return trimmed || BUILT_IN_EXTENSION_KEY;
  }
  function isConfigured(s) {
    return Boolean(getEffectiveApiKey(s));
  }

  // src/lib/steam-auth.ts
  var STORAGE_KEY = "steamId";
  async function getSteamId() {
    const data = await chrome.storage.local.get(STORAGE_KEY);
    return data[STORAGE_KEY] || null;
  }
  async function setSteamId(steamId) {
    await chrome.storage.local.set({ [STORAGE_KEY]: steamId });
  }
  async function clearSteamId() {
    await chrome.storage.local.remove(STORAGE_KEY);
  }
  function buildSteamOpenIdUrl(returnTo) {
    const params = new URLSearchParams({
      "openid.ns": "http://specs.openid.net/auth/2.0",
      "openid.mode": "checkid_setup",
      "openid.return_to": returnTo,
      "openid.realm": returnTo,
      "openid.identity": "http://specs.openid.net/auth/2.0/identifier_select",
      "openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select"
    });
    return `https://steamcommunity.com/openid/login?${params.toString()}`;
  }
  function extractSteamIdFromRedirect(redirectUrl) {
    try {
      const url = new URL(redirectUrl);
      const claimedId = url.searchParams.get("openid.claimed_id");
      if (!claimedId) return null;
      const match = claimedId.match(/\/id\/(\d+)$/);
      return match ? match[1] : null;
    } catch {
      return null;
    }
  }

  // src/lib/api.ts
  function toApiPayload(item) {
    const stickers = [];
    for (let i = 0; i < 5; i++) {
      const s = item.stickers.find((x) => x.slot === i);
      if (s && s.stickerId) {
        stickers.push({
          slot: i,
          schema: s.schema ?? i,
          stickerId: s.stickerId,
          wear: s.wear ?? 0,
          scale: s.scale ?? 1,
          rotation: s.rotation ?? 0,
          offsetX: s.offsetX ?? 0,
          offsetY: s.offsetY ?? 0,
          offsetZ: s.offsetZ ?? 0,
          pattern: s.pattern ?? 0,
          tintId: s.tintId ?? 0,
          wrappedSticker: s.wrappedSticker ?? 0,
          highlightReel: s.highlightReel ?? 0
        });
      } else {
        stickers.push({
          slot: i,
          schema: i,
          stickerId: 0,
          wear: 0,
          scale: 1,
          rotation: 0,
          offsetX: 0,
          offsetY: 0,
          offsetZ: 0,
          pattern: 0,
          tintId: 0,
          wrappedSticker: 0,
          highlightReel: 0
        });
      }
    }
    return {
      defindex: item.defindex,
      paintindex: item.paintindex,
      paintseed: item.paintseed,
      paintwear: item.paintwear,
      quality: item.quality,
      style: item.style,
      upgradeLevel: item.upgradeLevel,
      customName: item.customName,
      stickers,
      charm: item.charm ? {
        stickerId: item.charm.stickerId,
        pattern: item.charm.pattern,
        offsetX: item.charm.offsetX ?? 0,
        offsetY: item.charm.offsetY ?? 0,
        offsetZ: item.charm.offsetZ ?? 0
      } : null
    };
  }
  var ApiNotConfiguredError = class extends Error {
    constructor() {
      super("API not configured. Open the extension popup \u2192 Settings.");
      this.name = "ApiNotConfiguredError";
    }
  };
  async function submitSkin(item) {
    const settings = await getSettings();
    if (!isConfigured(settings)) throw new ApiNotConfiguredError();
    const payload = toApiPayload(item);
    const steamId = await getSteamId();
    if (steamId) payload.steamId = steamId;
    const url = `${API_BASE_URL}/skins`;
    const res = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": getEffectiveApiKey(settings)
      },
      body: JSON.stringify(payload)
    });
    if (!res.ok) {
      const body = await res.text().catch(() => "");
      throw new Error(`API ${res.status}: ${body || res.statusText}`);
    }
    const json = await res.json();
    if (!json.code) throw new Error("API response missing 'code' field");
    return json.code;
  }

  // src/lib/items.ts
  var GLOVE_DEFINDEXES = /* @__PURE__ */ new Set([
    4725,
    5027,
    5030,
    5031,
    5032,
    5033,
    5034,
    5035
  ]);
  var WEAPON_NAMES = {
    1: "Desert Eagle",
    2: "Dual Berettas",
    3: "Five-SeveN",
    4: "Glock-18",
    7: "AK-47",
    8: "AUG",
    9: "AWP",
    10: "FAMAS",
    11: "G3SG1",
    13: "Galil AR",
    14: "M249",
    16: "M4A4",
    17: "MAC-10",
    19: "P90",
    23: "MP5-SD",
    24: "UMP-45",
    25: "XM1014",
    26: "PP-Bizon",
    27: "MAG-7",
    28: "Negev",
    29: "Sawed-Off",
    30: "Tec-9",
    31: "Zeus x27",
    32: "P2000",
    33: "MP7",
    34: "MP9",
    35: "Nova",
    36: "P250",
    38: "SCAR-20",
    39: "SG 553",
    40: "SSG 08",
    42: "Knife",
    43: "Flashbang",
    44: "HE Grenade",
    45: "Smoke Grenade",
    46: "Molotov",
    47: "Decoy",
    48: "Incendiary",
    49: "C4",
    57: "CZ75-Auto",
    59: "R8 Revolver",
    60: "M4A1-S",
    61: "USP-S",
    63: "MP5-SD",
    500: "Bayonet",
    503: "Classic Knife",
    505: "Flip Knife",
    506: "Gut Knife",
    507: "Karambit",
    508: "M9 Bayonet",
    509: "Huntsman Knife",
    512: "Falchion Knife",
    514: "Bowie Knife",
    515: "Butterfly Knife",
    516: "Shadow Daggers",
    517: "Paracord Knife",
    518: "Survival Knife",
    519: "Ursus Knife",
    520: "Navaja Knife",
    521: "Nomad Knife",
    522: "Stiletto Knife",
    523: "Talon Knife",
    525: "Skeleton Knife",
    526: "Kukri Knife",
    4725: "Broken Fang Gloves",
    5027: "Bloodhound Gloves",
    5030: "Sport Gloves",
    5031: "Driver Gloves",
    5032: "Hand Wraps",
    5033: "Moto Gloves",
    5034: "Specialist Gloves",
    5035: "Hydra Gloves"
  };
  var WEAR_RANGES = {
    "Factory New": [0, 0.07],
    "Minimal Wear": [0.07, 0.15],
    "Field-Tested": [0.15, 0.38],
    "Well-Worn": [0.38, 0.45],
    "Battle-Scarred": [0.45, 1]
  };
  function getWearName(wear) {
    for (const [name, [min, max]] of Object.entries(WEAR_RANGES)) {
      if (wear >= min && wear < max) return name;
    }
    return "Battle-Scarred";
  }
  function getWeaponName(defindex) {
    return WEAPON_NAMES[defindex] ?? `Unknown (${defindex})`;
  }
  function isGlove(defindex) {
    return GLOVE_DEFINDEXES.has(defindex);
  }

  // src/lib/resolver.ts
  var BotUnreachableError = class extends Error {
    constructor() {
      super("Steam GC bot unreachable");
      this.name = "BotUnreachableError";
    }
  };
  var BotRateLimitError = class extends Error {
    constructor() {
      super("Bot rate limited (30 req/min). Slow down.");
      this.name = "BotRateLimitError";
    }
  };
  var BotGcTimeoutError = class extends Error {
    constructor() {
      super("Steam GC inspect timed out \u2014 try again in a few seconds.");
      this.name = "BotGcTimeoutError";
    }
  };
  async function resolveUnmaskedLink(link) {
    const settings = await getSettings();
    if (!isConfigured(settings)) {
      throw new Error("Extension misconfigured: built-in API key is empty.");
    }
    const url = `${BOT_BASE_URL}/resolve`;
    const ac = new AbortController();
    const timeout = setTimeout(() => ac.abort(), 3e4);
    let res;
    try {
      res = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-Key": getEffectiveApiKey(settings)
        },
        body: JSON.stringify({ link }),
        signal: ac.signal
      });
    } catch {
      throw new BotUnreachableError();
    } finally {
      clearTimeout(timeout);
    }
    if (res.status === 429) throw new BotRateLimitError();
    if (res.status === 502) throw new BotGcTimeoutError();
    if (!res.ok) {
      const body = await res.text().catch(() => "");
      throw new Error(`Bot ${res.status}: ${body || res.statusText}`);
    }
    const data = await res.json();
    return botResponseToDecodedItem(data);
  }
  function botResponseToDecodedItem(d) {
    const defindex = d.defindex ?? 0;
    const paintwear = d.paintwear ?? 0;
    const quality = d.quality ?? 0;
    const stickers = [];
    let cell = 0;
    for (const s of d.stickers ?? []) {
      if (!s || !s.stickerId) continue;
      if (cell >= 5) break;
      const protoSlot = typeof s.slot === "number" ? s.slot : cell;
      const rawSchema = typeof s.schema === "number" ? s.schema : protoSlot;
      if (rawSchema < 0 || rawSchema > 4) {
        console.warn(
          `[cs2-gencode] resolver: bot returned schema=${rawSchema} for sticker, clamping to 0..4. Raw sticker:`,
          s
        );
      }
      const schema = Math.max(0, Math.min(4, rawSchema));
      stickers.push({
        slot: cell++,
        schema,
        stickerId: s.stickerId,
        wear: s.wear ?? 0,
        scale: s.scale,
        rotation: s.rotation,
        offsetX: s.offsetX,
        offsetY: s.offsetY,
        offsetZ: s.offsetZ,
        pattern: s.pattern,
        tintId: s.tintId,
        wrappedSticker: s.wrappedSticker,
        highlightReel: s.highlightReel
      });
    }
    let charm = null;
    if (d.charm && d.charm.stickerId) {
      charm = {
        stickerId: d.charm.stickerId,
        pattern: d.charm.pattern ?? 0,
        offsetX: d.charm.offsetX,
        offsetY: d.charm.offsetY,
        offsetZ: d.charm.offsetZ
      };
    }
    return {
      defindex,
      paintindex: d.paintindex ?? 0,
      paintseed: d.paintseed ?? 0,
      paintwear,
      rarity: d.rarity ?? 0,
      quality,
      style: d.style ?? 0,
      upgradeLevel: d.upgradeLevel ?? 0,
      customName: d.customName ?? "",
      weaponName: getWeaponName(defindex),
      wearName: getWearName(paintwear),
      isGlove: isGlove(defindex),
      isStatTrak: quality === 9,
      stickers,
      charm
    };
  }

  // src/background/service-worker.ts
  chrome.runtime.onInstalled.addListener(() => {
    chrome.contextMenus.create({
      id: "convert-inspect-link",
      title: "Convert inspect link to !ngk code",
      contexts: ["link"]
    });
  });
  chrome.contextMenus.onClicked.addListener(async (info, tab) => {
    if (info.menuItemId !== "convert-inspect-link" || !info.linkUrl) return;
    if (!tab?.id) return;
    if (!/^steam:\/\/(?:run|rungame)\/730\//i.test(info.linkUrl)) return;
    chrome.tabs.sendMessage(tab.id, {
      type: "CONVERT_LINK",
      link: info.linkUrl
    });
  });
  var OFFSCREEN_URL = "offscreen.html";
  var OFFSCREEN_FULL_URL = chrome.runtime.getURL(OFFSCREEN_URL);
  async function ensureOffscreenDocument() {
    const hasDocument = chrome.offscreen.hasDocument;
    if (typeof hasDocument === "function") {
      if (await hasDocument.call(chrome.offscreen)) return;
    } else if (typeof chrome.runtime.getContexts === "function") {
      const ctxs = await chrome.runtime.getContexts({
        contextTypes: ["OFFSCREEN_DOCUMENT"],
        documentUrls: [OFFSCREEN_FULL_URL]
      });
      if (ctxs.length > 0) return;
    }
    try {
      await chrome.offscreen.createDocument({
        url: OFFSCREEN_URL,
        reasons: ["CLIPBOARD"],
        justification: "Write generated !ngk code to clipboard from right-click context menu, where transient user activation is unavailable."
      });
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      if (!/already/i.test(msg)) throw e;
    }
  }
  async function writeClipboardViaOffscreen(text) {
    await ensureOffscreenDocument();
    const res = await chrome.runtime.sendMessage({
      type: "OFFSCREEN_WRITE_CLIPBOARD",
      text
    });
    if (!res?.ok) {
      throw new Error(res?.error || "offscreen clipboard write failed");
    }
  }
  chrome.runtime.onMessage.addListener(
    (msg, _sender, sendResponse) => {
      if (msg?.type === "SUBMIT_SKIN") {
        submitSkin(msg.item).then((code) => {
          const res = { ok: true, code };
          sendResponse(res);
        }).catch((e) => {
          const res = {
            ok: false,
            error: e instanceof Error ? e.message : String(e),
            notConfigured: e instanceof ApiNotConfiguredError
          };
          sendResponse(res);
        });
        return true;
      }
      if (msg?.type === "RESOLVE_LINK") {
        resolveUnmaskedLink(msg.link).then((item) => {
          const res = { ok: true, item };
          sendResponse(res);
        }).catch((e) => {
          let errorKind = "other";
          if (e instanceof BotUnreachableError) errorKind = "unreachable";
          else if (e instanceof BotRateLimitError) errorKind = "rateLimit";
          else if (e instanceof BotGcTimeoutError) errorKind = "gcTimeout";
          const res = {
            ok: false,
            error: e instanceof Error ? e.message : String(e),
            errorKind
          };
          sendResponse(res);
        });
        return true;
      }
      if (msg?.type === "WRITE_CLIPBOARD") {
        writeClipboardViaOffscreen(msg.text).then(() => {
          const res = { ok: true };
          sendResponse(res);
        }).catch((e) => {
          const res = {
            ok: false,
            error: e instanceof Error ? e.message : String(e)
          };
          sendResponse(res);
        });
        return true;
      }
      if (msg?.type === "STEAM_LOGIN") {
        const redirectUrl = chrome.identity.getRedirectURL();
        const authUrl = buildSteamOpenIdUrl(redirectUrl);
        chrome.identity.launchWebAuthFlow({ url: authUrl, interactive: true }).then(async (responseUrl) => {
          if (!responseUrl) {
            const res2 = {
              ok: false,
              error: "Auth cancelled"
            };
            sendResponse(res2);
            return;
          }
          const steamId = extractSteamIdFromRedirect(responseUrl);
          if (!steamId) {
            const res2 = {
              ok: false,
              error: "Could not extract Steam ID"
            };
            sendResponse(res2);
            return;
          }
          await setSteamId(steamId);
          const res = { ok: true, steamId };
          sendResponse(res);
        }).catch((e) => {
          const res = {
            ok: false,
            error: e instanceof Error ? e.message : String(e)
          };
          sendResponse(res);
        });
        return true;
      }
      if (msg?.type === "STEAM_LOGOUT") {
        clearSteamId().then(() => sendResponse({ ok: true }));
        return true;
      }
      return false;
    }
  );
})();
