ZZZ Seelie 数据同步

绝区零 Seelie 网站数据同步脚本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         ZZZ Seelie 数据同步
// @namespace    github.com/owwkmidream
// @version      1.2.3
// @author       owwkmidream
// @description  绝区零 Seelie 网站数据同步脚本
// @license      MIT
// @icon         https://zzz.seelie.me/img/logo.svg
// @homepageURL  https://github.com/owwkmidream/zzz-seelie-sync
// @supportURL   https://github.com/owwkmidream/zzz-seelie-sync/issues
// @match        https://zzz.seelie.me/*
// @match        https://do-not-exist.mihoyo.com/
// @require      https://fastly.jsdelivr.net/npm/@trim21/[email protected]
// @connect      act-api-takumi.mihoyo.com
// @connect      api-takumi-record.mihoyo.com
// @connect      public-data-api.mihoyo.com
// @connect      api-takumi.mihoyo.com
// @grant        GM.cookie
// @grant        GM.xmlHttpRequest
// @run-at       document-end
// ==/UserScript==

(function (GM_fetch) {
  'use strict';

  class Logger {
    prefix;
    timestamp;
    showLocation;
    colors;
    fileColorMap = /* @__PURE__ */ new Map();
    constructor(options = {}) {
      this.prefix = options.prefix || "[zzz-seelie-sync]";
      this.timestamp = options.timestamp ?? true;
      this.showLocation = options.showLocation ?? true;
      this.colors = {
        log: "#333333",
        info: "#2196F3",
        warn: "#FF9800",
        error: "#F44336",
        debug: "#9C27B0",
        ...options.colors
      };
    }
    /**
     * 生成随机颜色
     */
    generateRandomColor() {
      const colors = [
        "#E91E63",
        "#9C27B0",
        "#673AB7",
        "#3F51B5",
        "#2196F3",
        "#03A9F4",
        "#00BCD4",
        "#009688",
        "#4CAF50",
        "#8BC34A",
        "#CDDC39",
        "#FFC107",
        "#FF9800",
        "#FF5722",
        "#795548",
        "#607D8B",
        "#E53935",
        "#D81B60",
        "#8E24AA",
        "#5E35B1"
      ];
      return colors[Math.floor(Math.random() * colors.length)];
    }
    /**
     * 获取文件颜色(为每个文件分配固定的随机颜色)
     */
    getFileColor(fileName) {
      if (!this.fileColorMap.has(fileName)) {
        this.fileColorMap.set(fileName, this.generateRandomColor());
      }
      return this.fileColorMap.get(fileName);
    }
    /**
     * 获取调用位置信息
     */
    getLocationInfo() {
      try {
        const stack = new Error().stack;
        if (!stack) return null;
        const lines = stack.split("\n");
        for (let i = 3; i < Math.min(lines.length, 8); i++) {
          const targetLine = lines[i];
          if (!targetLine) continue;
          if (targetLine.includes("Logger.") || targetLine.includes("formatMessage") || targetLine.includes("getLocationInfo")) {
            continue;
          }
          const patterns = [
            /at.*?\((.+):(\d+):(\d+)\)/,
            // Chrome with function name
            /at\s+(.+):(\d+):(\d+)/,
            // Chrome without function name
            /@(.+):(\d+):(\d+)/,
            // Firefox/Safari
            /(.+):(\d+):(\d+)$/
            // Fallback pattern
          ];
          for (const pattern of patterns) {
            const match = targetLine.match(pattern);
            if (match) {
              const fullPath = match[1];
              const lineNumber = parseInt(match[2], 10);
              const columnNumber = parseInt(match[3], 10);
              if (!fullPath || fullPath.includes("chrome-extension://") || fullPath.includes("moz-extension://")) {
                continue;
              }
              const fileName = fullPath.split("/").pop() || fullPath.split("\\").pop() || fullPath;
              if (fileName && !isNaN(lineNumber) && !isNaN(columnNumber)) {
                return {
                  fileName,
                  lineNumber,
                  columnNumber
                };
              }
            }
          }
        }
        return null;
      } catch {
        return null;
      }
    }
    formatMessage(level, color, ...args) {
      const timestamp = this.timestamp ? `[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}]` : "";
      const location = this.showLocation ? this.getLocationInfo() : null;
      let prefix = `${timestamp} ${this.prefix} [${level.toUpperCase()}]`;
      let locationStr = "";
      let locationColor = "";
      if (location) {
        locationStr = ` [${location.fileName}:${location.lineNumber}]`;
        locationColor = this.getFileColor(location.fileName);
      }
      if (typeof window !== "undefined") {
        if (location) {
          return [
            `%c${prefix}%c${locationStr}`,
            `color: ${color}; font-weight: bold;`,
            `color: ${locationColor}; font-weight: bold; font-style: italic;`,
            ...args
          ];
        } else {
          return [
            `%c${prefix}`,
            `color: ${color}; font-weight: bold;`,
            ...args
          ];
        }
      }
      return [prefix + locationStr, ...args];
    }
    /**
     * 普通日志输出
     */
    log(...args) {
      console.log(...this.formatMessage("log", this.colors.log, ...args));
    }
    /**
     * 信息日志输出
     */
    info(...args) {
      console.info(...this.formatMessage("info", this.colors.info, ...args));
    }
    /**
     * 警告日志输出
     */
    warn(...args) {
      console.warn(...this.formatMessage("warn", this.colors.warn, ...args));
    }
    /**
     * 错误日志输出
     */
    error(...args) {
      console.error(...this.formatMessage("error", this.colors.error, ...args));
    }
    /**
     * 调试日志输出 (仅在开发环境下输出)
     */
    debug(...args) {
    }
    /**
     * 表格输出
     */
    table(data, columns) {
      if (this.timestamp || this.prefix) {
        this.info("Table data:");
      }
      console.table(data, columns);
    }
    /**
     * 分组开始
     */
    group(label) {
      const formattedLabel = label ? this.formatMessage("group", this.colors.info, label)[2] : void 0;
      console.group(formattedLabel);
    }
    /**
     * 折叠分组开始
     */
    groupCollapsed(label) {
      const formattedLabel = label ? this.formatMessage("group", this.colors.info, label)[2] : void 0;
      console.groupCollapsed(formattedLabel);
    }
    /**
     * 分组结束
     */
    groupEnd() {
      console.groupEnd();
    }
    /**
     * 计时开始
     */
    time(label) {
      console.time(label);
    }
    /**
     * 计时结束
     */
    timeEnd(label) {
      console.timeEnd(label);
    }
    /**
     * 清空控制台
     */
    clear() {
      console.clear();
    }
    /**
     * 创建子 Logger 实例
     */
    createChild(childPrefix, options) {
      const childLogger = new Logger({
        prefix: `${this.prefix}:${childPrefix}`,
        timestamp: this.timestamp,
        showLocation: this.showLocation,
        colors: this.colors,
        ...options
      });
      childLogger.fileColorMap = this.fileColorMap;
      return childLogger;
    }
  }
  const logger = new Logger({
    prefix: "[Seelie]",
    timestamp: true,
    showLocation: true,
    colors: {
      log: "#4CAF50",
      info: "#2196F3",
      warn: "#FF9800",
      error: "#F44336",
      debug: "#9C27B0"
    }
  });
  logger.log.bind(logger);
  logger.info.bind(logger);
  logger.warn.bind(logger);
  logger.error.bind(logger);
  let pendingHooks = [];
  let routerObserver = null;
  let isObserving = false;
  function findVueRouter() {
    const appElement = document.querySelector("#app");
    if (!appElement?.__vue_app__) {
      logger.debug("🔍 未找到 Vue App 实例,可能还在加载中...");
      return null;
    }
    logger.debug("🔍 查找 Vue Router 实例...");
    const router = appElement.__vue_app__.config?.globalProperties?.$router;
    if (router) {
      if (typeof router.afterEach === "function" && typeof router.beforeEach === "function" && typeof router.push === "function") {
        logger.info("✓ 从 __vue_app__.config.globalProperties.$router 找到 Router 实例");
        logger.debug("Router 实例:", router);
        return router;
      }
    }
    const context = appElement.__vue_app__._context;
    if (context?.provides) {
      logger.debug("🔍 尝试从 provides 查找 Router...");
      const provides = context.provides;
      const symbols = Object.getOwnPropertySymbols(provides);
      for (const symbol of symbols) {
        const value = provides[symbol];
        if (value && typeof value === "object") {
          const potentialRouter = value;
          if (typeof potentialRouter.afterEach === "function" && typeof potentialRouter.beforeEach === "function" && typeof potentialRouter.push === "function") {
            logger.info("✓ 从 provides 找到 Router 实例:", symbol.toString());
            logger.debug("Router 实例:", value);
            return potentialRouter;
          }
        }
      }
    }
    logger.debug("🔍 未找到 Vue Router 实例,可能还在初始化中...");
    return null;
  }
  function stopRouterObserver() {
    if (routerObserver) {
      routerObserver.disconnect();
      routerObserver = null;
    }
    isObserving = false;
  }
  function startRouterObserver() {
    const timeout = 3e3;
    if (isObserving || routerObserver) {
      return;
    }
    logger.debug("👀 启动 Vue Router 观察器...");
    isObserving = true;
    routerObserver = new MutationObserver(() => {
      const router = findVueRouter();
      if (router) {
        logger.info("✓ Vue Router 已加载,处理待注册的 Hook...");
        stopRouterObserver();
        processPendingHooks(router);
      }
    });
    routerObserver.observe(document.querySelector("#app"), {
      childList: false,
      subtree: false,
      attributes: true
    });
    setTimeout(() => {
      if (isObserving) {
        logger.warn("⚠️ Vue Router 观察器超时,停止观察");
        stopRouterObserver();
        processPendingHooks(null);
      }
    }, timeout);
  }
  function processPendingHooks(router) {
    logger.debug(`🔄 处理 ${pendingHooks.length} 个待注册的 Hook...`);
    const hooks = [...pendingHooks];
    pendingHooks = [];
    hooks.forEach(({ callback, options, unwatchRef }) => {
      if (router) {
        const { unwatch } = registerRouterHook(router, callback, options);
        unwatchRef.current = unwatch;
      } else {
        logger.warn("⚠️ Vue Router 未找到,Hook 注册失败");
        unwatchRef.current = () => {
        };
      }
    });
  }
  function registerRouterHook(router, callback, options) {
    const { delay = 100, immediate = false } = options;
    if (immediate) {
      setTimeout(() => {
        const currentRoute = router.currentRoute?.value || router.currentRoute;
        callback(currentRoute, null);
      }, delay);
    }
    const unwatch = router.afterEach((to, from) => {
      logger.debug("🔄 路由变化检测到:", from?.path, "->", to?.path);
      setTimeout(() => {
        callback(to, from);
      }, delay);
    });
    return {
      router,
      unwatch,
      getCurrentRoute: () => {
        const currentRoute = router.currentRoute?.value || router.currentRoute;
        return currentRoute;
      }
    };
  }
  function useRouterWatcher(callback, options = {}) {
    logger.debug("🚦 设置路由监听 Hook...");
    const router = findVueRouter();
    if (router) {
      logger.debug("✓ Vue Router 已存在,直接注册 Hook");
      const result = registerRouterHook(router, callback, options);
      return result;
    }
    logger.debug("⏳ Vue Router 未找到,设置延迟注册...");
    const unwatchRef = { current: null };
    pendingHooks.push({
      callback,
      options,
      unwatchRef
    });
    startRouterObserver();
    return {
      router: null,
      unwatch: () => {
        if (unwatchRef.current) {
          unwatchRef.current();
        }
      },
      getCurrentRoute: () => {
        const currentRouter = findVueRouter();
        if (currentRouter) {
          const currentRoute = currentRouter.currentRoute?.value || currentRouter.currentRoute;
          return currentRoute;
        }
        return void 0;
      }
    };
  }
  class ComponentInjector {
    component = null;
    config;
    factory;
    isCreating = false;
    createPromise = null;
    constructor(config, factory) {
      this.config = config;
      this.factory = factory;
    }
    /**
     * 检查组件是否已存在
     */
    checkExistence() {
      const targetContainer = document.querySelector(this.config.targetSelector);
      if (!targetContainer) return false;
      const componentElement = targetContainer.querySelector(this.config.componentSelector);
      return componentElement !== null;
    }
    /**
     * 检查创建条件
     */
    checkCondition() {
      const targetExists = document.querySelector(this.config.targetSelector) !== null;
      if (!targetExists) return false;
      if (this.config.condition && !this.config.condition()) {
        return false;
      }
      if (this.config.routePattern) {
        const currentPath = window.location.pathname;
        if (typeof this.config.routePattern === "string") {
          return currentPath.includes(this.config.routePattern);
        } else {
          return this.config.routePattern.test(currentPath);
        }
      }
      return true;
    }
    /**
     * 尝试创建组件
     */
    async tryCreate() {
      if (this.isCreating && this.createPromise) {
        logger.debug(`⏳ [${this.config.id}] 组件正在创建中,等待完成`);
        await this.createPromise;
        return;
      }
      if (!this.checkCondition()) {
        logger.debug(`🚫 [${this.config.id}] 条件检查失败,跳过创建`);
        return;
      }
      if (this.checkExistence()) {
        logger.debug(`✅ [${this.config.id}] 组件已存在,跳过创建`);
        return;
      }
      this.createPromise = this.createComponent();
      await this.createPromise;
    }
    /**
     * 创建组件
     */
    async createComponent() {
      if (this.isCreating) {
        logger.debug(`⚠️ [${this.config.id}] 组件已在创建中,跳过重复创建`);
        return;
      }
      this.isCreating = true;
      try {
        if (this.checkExistence()) {
          logger.debug(`✅ [${this.config.id}] 组件已存在,取消创建`);
          return;
        }
        this.destroyComponent();
        this.component = await this.factory();
        await this.component.init();
        logger.debug(`✅ [${this.config.id}] 组件创建成功`);
      } catch (error) {
        logger.error(`❌ [${this.config.id}] 创建组件失败:`, error);
        this.component = null;
      } finally {
        this.isCreating = false;
        this.createPromise = null;
      }
    }
    /**
     * 检查并重新创建组件
     */
    async checkAndRecreate() {
      if (this.isCreating) {
        logger.debug(`⏳ [${this.config.id}] 组件正在创建中,跳过检查`);
        return;
      }
      const shouldExist = this.checkCondition();
      const doesExist = this.checkExistence();
      if (shouldExist && !doesExist) {
        logger.debug(`🔧 [${this.config.id}] 组件缺失,重新创建组件`);
        await this.tryCreate();
      } else if (!shouldExist && doesExist) {
        logger.debug(`🗑️ [${this.config.id}] 条件不满足,销毁组件`);
        this.destroyComponent();
      }
    }
    /**
     * 销毁组件
     */
    destroyComponent() {
      if (this.isCreating && this.createPromise) {
        logger.debug(`⏳ [${this.config.id}] 等待创建完成后销毁`);
        this.createPromise.then(() => {
          if (this.component) {
            this.component.destroy();
            this.component = null;
            logger.debug(`🗑️ [${this.config.id}] 组件已销毁(延迟)`);
          }
        });
        return;
      }
      if (this.component) {
        this.component.destroy();
        this.component = null;
        logger.debug(`🗑️ [${this.config.id}] 组件已销毁`);
      }
    }
    /**
     * 刷新组件
     */
    async refreshComponent() {
      if (this.component && this.component.refresh) {
        await this.component.refresh();
        logger.debug(`🔄 [${this.config.id}] 组件已刷新`);
      }
    }
    /**
     * 处理路由变化
     */
    async handleRouteChange(_to, _from) {
      await this.checkAndRecreate();
    }
    /**
     * 处理 DOM 变化
     */
    async handleDOMChange(_mutations) {
      await this.checkAndRecreate();
    }
    /**
     * 清理资源
     */
    cleanup() {
      this.isCreating = false;
      this.createPromise = null;
      this.destroyComponent();
    }
    /**
     * 获取组件实例
     */
    getComponent() {
      return this.component;
    }
    /**
     * 检查组件是否存在
     */
    hasComponent() {
      return this.component !== null && this.checkExistence();
    }
    /**
     * 检查是否正在创建中
     */
    isCreatingComponent() {
      return this.isCreating;
    }
    /**
     * 获取配置
     */
    getConfig() {
      return this.config;
    }
  }
  class DOMInjectorManager {
    injectors = /* @__PURE__ */ new Map();
    domObserver = null;
    routerUnwatch = null;
    isInitialized = false;
    options;
    constructor(options = {}) {
      this.options = {
        observerConfig: {
          childList: true,
          subtree: true
        },
        enableGlobalRouterWatch: true,
        routerDelay: 100,
        ...options
      };
    }
    /**
     * 注册组件注入器
     */
    register(config, factory) {
      if (this.injectors.has(config.id)) {
        logger.warn(`⚠️ 注入器 [${config.id}] 已存在,将被覆盖`);
        this.unregister(config.id);
      }
      const injector = new ComponentInjector(config, factory);
      this.injectors.set(config.id, injector);
      logger.debug(`📝 注册组件注入器: [${config.id}]`);
      if (this.isInitialized) {
        injector.tryCreate();
      }
      return injector;
    }
    /**
     * 注销组件注入器
     */
    unregister(id) {
      const injector = this.injectors.get(id);
      if (injector) {
        injector.cleanup();
        this.injectors.delete(id);
        logger.debug(`🗑️ 注销组件注入器: [${id}]`);
        return true;
      }
      return false;
    }
    /**
     * 获取注入器
     */
    getInjector(id) {
      return this.injectors.get(id) || null;
    }
    /**
     * 初始化管理器
     */
    init() {
      if (this.isInitialized) {
        logger.warn("⚠️ DOM 注入管理器已经初始化");
        return;
      }
      logger.debug("🎯 初始化 DOM 注入管理器");
      if (this.options.enableGlobalRouterWatch) {
        this.setupGlobalRouterWatcher();
      }
      this.setupDOMObserver();
      this.createAllComponents();
      this.isInitialized = true;
    }
    /**
     * 设置全局路由监听
     */
    setupGlobalRouterWatcher() {
      const { unwatch } = useRouterWatcher(
        async (to, from) => {
          logger.debug("🔄 全局路由变化检测到:", from?.path, "->", to?.path);
          await this.handleGlobalRouteChange(to, from);
        },
        {
          delay: this.options.routerDelay,
          immediate: false
        }
      );
      this.routerUnwatch = unwatch;
      logger.debug("✅ 全局路由监听设置完成");
    }
    /**
     * 设置 DOM 观察器
     */
    setupDOMObserver() {
      let debounceTimer = null;
      let isProcessing = false;
      let pendingMutations = [];
      let lastDebugTime = 0;
      const debugLogInterval = 3e3;
      this.domObserver = new MutationObserver(async (mutations) => {
        pendingMutations.push(...mutations);
        if (debounceTimer) {
          clearTimeout(debounceTimer);
        }
        debounceTimer = setTimeout(async () => {
          if (isProcessing) {
            logger.debug("🔍 DOM 变化处理中,跳过本次处理");
            return;
          }
          isProcessing = true;
          const currentMutations = [...pendingMutations];
          pendingMutations = [];
          try {
            const now = Date.now();
            if (now - lastDebugTime >= debugLogInterval) {
              lastDebugTime = now;
              logger.debug(`🔍 检测到 ${currentMutations.length} 个 DOM 变化,通知所有组件`);
            }
            await this.handleGlobalDOMChange(currentMutations);
          } finally {
            isProcessing = false;
            debounceTimer = null;
          }
        }, 100);
      });
      this.domObserver.observe(document.body, this.options.observerConfig);
      logger.debug("✅ DOM 观察器设置完成");
    }
    /**
     * 处理全局路由变化
     */
    async handleGlobalRouteChange(to, from) {
      const promises = Array.from(this.injectors.values()).map(
        (injector) => injector.handleRouteChange(to, from)
      );
      await Promise.allSettled(promises);
    }
    /**
     * 处理全局 DOM 变化
     */
    async handleGlobalDOMChange(mutations) {
      const promises = Array.from(this.injectors.values()).map(
        (injector) => injector.handleDOMChange(mutations)
      );
      await Promise.allSettled(promises);
    }
    /**
     * 创建所有组件
     */
    async createAllComponents() {
      const promises = Array.from(this.injectors.values()).map((injector) => injector.tryCreate());
      await Promise.allSettled(promises);
    }
    /**
     * 刷新所有组件
     */
    async refreshAllComponents() {
      const promises = Array.from(this.injectors.values()).map((injector) => injector.refreshComponent());
      await Promise.allSettled(promises);
    }
    /**
     * 刷新指定组件
     */
    async refreshComponent(id) {
      const injector = this.injectors.get(id);
      if (injector) {
        await injector.refreshComponent();
      }
    }
    /**
     * 销毁管理器
     */
    destroy() {
      logger.debug("🗑️ 销毁 DOM 注入管理器");
      for (const injector of this.injectors.values()) {
        injector.cleanup();
      }
      this.injectors.clear();
      if (this.routerUnwatch) {
        this.routerUnwatch();
        this.routerUnwatch = null;
      }
      if (this.domObserver) {
        this.domObserver.disconnect();
        this.domObserver = null;
      }
      this.isInitialized = false;
    }
    /**
     * 获取所有注入器 ID
     */
    getInjectorIds() {
      return Array.from(this.injectors.keys());
    }
    /**
     * 获取注入器数量
     */
    getInjectorCount() {
      return this.injectors.size;
    }
    /**
     * 检查是否已初始化
     */
    isInit() {
      return this.isInitialized;
    }
  }
  const domInjector = new DOMInjectorManager({
    enableGlobalRouterWatch: true,
    routerDelay: 200,
    observerConfig: {
      childList: true,
      subtree: true
    }
  });
  var _GM = /* @__PURE__ */ (() => typeof GM != "undefined" ? GM : void 0)();
  const DEVICE_INFO_KEY = "zzz_device_info";
  const NAP_CULTIVATE_TOOL_URL = "https://act-api-takumi.mihoyo.com/event/nap_cultivate_tool";
  const GAME_RECORD_URL = "https://api-takumi-record.mihoyo.com/event/game_record_zzz/api/zzz";
  const DEVICE_FP_URL = "https://public-data-api.mihoyo.com/device-fp/api/getFp";
  const GAME_ROLE_URL = "https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=nap_cn";
  const NAP_TOEKN_URL = "https://api-takumi.mihoyo.com/common/badge/v1/login/account";
  let NapTokenInitialized = false;
  let userInfoCache = null;
  let deviceInfoCache = {
    deviceId: generateUUID(),
    deviceFp: "0000000000000",
    timestamp: Date.now()
  };
  let deviceInfoPromise = null;
  const appVer = "2.85.1";
  const defaultHeaders = {
    "Accept": "application/json",
    "User-Agent": `Mozilla/5.0 (Linux; Android 13; Pixel 5 Build/TQ3A.230901.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/118.0.0.0 Mobile Safari/537.36 miHoYoBBS/${appVer}`
  };
  async function getZZZHeaderWithDevice() {
    const deviceInfo = await getDeviceInfo();
    return {
      ...defaultHeaders,
      "Referer": "https://act.mihoyo.com/",
      "x-rpc-app_version": appVer,
      "x-rpc-client_type": "5",
      "x-rpc-device_fp": deviceInfo.deviceFp,
      "x-rpc-device_id": deviceInfo.deviceId
    };
  }
  async function initializeNapToken() {
    if (NapTokenInitialized) {
      return;
    }
    logger.debug("🔄 初始化 nap_token cookie...");
    try {
      const rolesResponse = await GM_fetch(GAME_ROLE_URL, {
        method: "GET",
        headers: defaultHeaders
      });
      if (!rolesResponse.ok) {
        throw new Error(`获取用户角色失败: HTTP ${rolesResponse.status}`);
      }
      const rolesData = await rolesResponse.json();
      if (rolesData.retcode !== 0) {
        throw new Error(`获取用户角色失败: ${rolesData.message}`);
      }
      if (!rolesData.data?.list || rolesData.data.list.length === 0) {
        throw new Error("未找到绝区零游戏角色");
      }
      const roleInfo = rolesData.data.list[0];
      logger.debug(`🎮 找到角色: ${roleInfo.nickname} (UID: ${roleInfo.game_uid}, 等级: ${roleInfo.level})`);
      const tokenResponse = await GM_fetch(NAP_TOEKN_URL, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          ...defaultHeaders
        },
        body: JSON.stringify({
          region: roleInfo.region,
          uid: roleInfo.game_uid,
          game_biz: roleInfo.game_biz
        })
      });
      if (!tokenResponse.ok) {
        throw new Error(`设置 nap_token 失败: HTTP ${tokenResponse.status}`);
      }
      const tokenData = await tokenResponse.json();
      if (tokenData.retcode !== 0) {
        throw new Error(`设置 nap_token 失败: ${tokenData.message}`);
      }
      userInfoCache = {
        uid: roleInfo.game_uid,
        nickname: roleInfo.nickname,
        level: roleInfo.level,
        region: roleInfo.region,
        accountId: roleInfo.game_uid
        // 使用 game_uid 作为 accountId
      };
      logger.debug("✅ nap_token cookie 初始化完成");
      logger.info(`👤 用户信息: ${userInfoCache.nickname} (UID: ${userInfoCache.uid}, 等级: ${userInfoCache.level})`);
      NapTokenInitialized = true;
    } catch (error) {
      logger.error("❌ 初始化 nap_token 失败:", error);
      throw error;
    }
  }
  async function ensureUserInfo() {
    if (!userInfoCache) {
      await initializeNapToken();
    }
  }
  async function request(endpoint, baseUrl, options = {}) {
    const { method = "GET", params = {}, body, headers = {} } = options;
    if (baseUrl === NAP_CULTIVATE_TOOL_URL) {
      await initializeNapToken();
    }
    let url = `${baseUrl}${endpoint}`;
    if (Object.keys(params).length > 0) {
      const searchParams = new URLSearchParams();
      Object.entries(params).forEach(([key, value]) => {
        searchParams.append(key, String(value));
      });
      url += `?${searchParams.toString()}`;
    }
    const deviceFpErrorCodes = [1034, 5003, 10035, 10041, 10053];
    const executeRequest = async (isRetry = false) => {
      const zzzHeaders = await getZZZHeaderWithDevice();
      const finalHeaders = {
        ...zzzHeaders,
        ...headers
      };
      if (finalHeaders["x-rpc-device_fp"] === "0000000000000") {
        throw new Error("❌ 设备指纹有误,请检查");
      }
      logger.debug(`🌐 请求 ${method} ${url}${isRetry ? " (重试)" : ""}`);
      try {
        const payload = [url, {
          method,
          headers: finalHeaders,
          body: body ? JSON.stringify(body) : void 0
        }];
        const response = await GM_fetch(...payload);
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        const data = await response.json();
        if (data.retcode !== 0) {
          if (deviceFpErrorCodes.includes(data.retcode) && !isRetry) {
            logger.warn(`⚠️ 检测到设备指纹错误码 ${data.retcode}: ${data.message},正在刷新设备指纹...`);
            try {
              await getDeviceFingerprint();
              logger.debug("✅ 设备指纹刷新完成,准备重试请求");
              return await executeRequest(true);
            } catch (fpError) {
              logger.error("❌ 设备指纹刷新失败:", fpError);
              throw new Error(`设备指纹刷新失败,原始错误: API Error ${data.retcode}: ${data.message}`);
            }
          }
          logger.error("❌ 请求失败\n请求:", payload, "\n响应:", response, data);
          throw new Error(`API Error ${data.retcode}: ${data.message}`);
        }
        logger.debug(`✅ 请求成功: ${payload[0]}, ${data.retcode}: ${data.message}`);
        return data;
      } catch (error) {
        if (error instanceof Error && error.message.includes("API Error")) {
          throw error;
        }
        logger.error(`❌ 请求失败:`, error);
        throw error;
      }
    };
    return await executeRequest();
  }
  async function getDeviceFingerprint() {
    const mysCookies = await _GM.cookie.list({ url: "https://do-not-exist.mihoyo.com/" });
    if (mysCookies.length !== 0) {
      for (const ck of mysCookies) {
        if (ck.name === "_MHYUUID") {
          logger.debug("🔐 从米游社获取到UUID", ck.value);
          deviceInfoCache.deviceId = ck.value;
        }
      }
    }
    if (!deviceInfoCache) {
      throw new Error("设备信息缓存未初始化");
    }
    const productName = generateProductName();
    const requestBody = {
      device_id: generateSeedId(),
      seed_id: generateUUID(),
      seed_time: Date.now().toString(),
      platform: "2",
      device_fp: deviceInfoCache.deviceFp,
      app_name: "bbs_cn",
      ext_fields: `{"proxyStatus":0,"isRoot":0,"romCapacity":"512","deviceName":"Pixel5","productName":"${productName}","romRemain":"512","hostname":"db1ba5f7c000000","screenSize":"1080x2400","isTablet":0,"aaid":"","model":"Pixel5","brand":"google","hardware":"windows_x86_64","deviceType":"redfin","devId":"REL","serialNumber":"unknown","sdCapacity":125943,"buildTime":"1704316741000","buildUser":"cloudtest","simState":0,"ramRemain":"124603","appUpdateTimeDiff":1716369357492,"deviceInfo":"google\\/${productName}\\/redfin:13\\/TQ3A.230901.001\\/2311.40000.5.0:user\\/release-keys","vaid":"","buildType":"user","sdkVersion":"33","ui_mode":"UI_MODE_TYPE_NORMAL","isMockLocation":0,"cpuType":"arm64-v8a","isAirMode":0,"ringMode":2,"chargeStatus":3,"manufacturer":"Google","emulatorStatus":0,"appMemory":"512","osVersion":"13","vendor":"unknown","accelerometer":"","sdRemain":123276,"buildTags":"release-keys","packageName":"com.mihoyo.hyperion","networkType":"WiFi","oaid":"","debugStatus":1,"ramCapacity":"125943","magnetometer":"","display":"TQ3A.230901.001","appInstallTimeDiff":1706444666737,"packageVersion":"2.20.2","gyroscope":"","batteryStatus":85,"hasKeyboard":10,"board":"windows"}`,
      bbs_device_id: deviceInfoCache.deviceId
    };
    logger.debug(`🔐 获取设备指纹,设备ID: ${deviceInfoCache.deviceId}`);
    try {
      const response = await GM_fetch(`${DEVICE_FP_URL}`, {
        method: "POST",
        headers: {
          ...defaultHeaders,
          "Content-Type": "application/json"
        },
        body: JSON.stringify(requestBody)
      });
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
      const data = await response.json();
      if (data.retcode !== 0 || data.data.code !== 200) {
        throw new Error(`设备指纹获取失败 ${data.retcode}: ${data.message}`);
      }
      deviceInfoCache.deviceFp = data.data.device_fp;
      deviceInfoCache.timestamp = Date.now();
      localStorage.setItem(DEVICE_INFO_KEY, JSON.stringify(deviceInfoCache));
      logger.debug(`✅ 设备指纹获取成功并更新缓存: ${data.data.device_fp}`);
    } catch (error) {
      logger.error(`❌ 设备指纹获取失败:`, error);
      throw error;
    }
  }
  function generateProductName() {
    const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    let result = "";
    for (let i = 0; i < 6; i++) {
      result += chars[Math.floor(Math.random() * chars.length)];
    }
    return result;
  }
  function generateUUID() {
    if (typeof crypto !== "undefined" && crypto.randomUUID) {
      return crypto.randomUUID();
    }
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0;
      const v = c === "x" ? r : r & 3 | 8;
      return v.toString(16);
    });
  }
  function generateSeedId() {
    return generateHexString(16);
  }
  function generateHexString(length) {
    const bytes = new Uint8Array(Math.ceil(length / 2));
    if (typeof crypto !== "undefined" && crypto.getRandomValues) {
      crypto.getRandomValues(bytes);
    } else {
      for (let i = 0; i < bytes.length; i++) {
        bytes[i] = Math.floor(Math.random() * 256);
      }
    }
    const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
    return hex.substring(0, length);
  }
  async function getDeviceInfo(refresh) {
    if (deviceInfoPromise) {
      return deviceInfoPromise;
    }
    deviceInfoPromise = (async () => {
      const stored = localStorage.getItem(DEVICE_INFO_KEY);
      if (stored) {
        try {
          const storedDeviceInfo = JSON.parse(stored);
          logger.debug("📱 从localStorage获取设备信息:", storedDeviceInfo);
          deviceInfoCache = storedDeviceInfo;
        } catch (error) {
          logger.warn("⚠️ 解析设备信息失败,将重新生成:", error);
        }
      }
      let needRefresh = false;
      if (refresh === true) {
        needRefresh = true;
        logger.debug("📱 强制刷新设备指纹");
      } else if (refresh === false) {
        needRefresh = false;
        logger.debug("📱 跳过设备指纹刷新");
      } else {
        const now = Date.now();
        const threeDaysInMs = 3 * 24 * 60 * 60 * 1e3;
        if (deviceInfoCache.deviceFp === "0000000000000") {
          needRefresh = true;
          logger.debug("📱 设备指纹为初始值,需要获取真实指纹");
        } else if (now - deviceInfoCache.timestamp > threeDaysInMs) {
          needRefresh = true;
          logger.debug("📱 设备信息超过3天,需要刷新");
        } else {
          logger.debug("📱 设备信息仍在有效期内");
        }
      }
      if (needRefresh) {
        try {
          await getDeviceFingerprint();
          logger.debug("✅ 设备指纹刷新完成");
        } catch (error) {
          logger.error("❌ 设备指纹刷新失败:", error);
          throw error;
        }
      }
      return deviceInfoCache;
    })();
    const result = await deviceInfoPromise;
    deviceInfoPromise = null;
    return result;
  }
  function getUserInfo() {
    return userInfoCache;
  }
  async function initializeUserInfo() {
    await ensureUserInfo();
    return userInfoCache;
  }
  async function refreshDeviceInfo() {
    logger.debug("🔄 开始刷新设备信息...");
    const newDeviceInfo = await getDeviceInfo(true);
    logger.debug("✅ 设备信息刷新完成:", newDeviceInfo);
  }
  async function resolveUserInfo(uid, region) {
    await ensureUserInfo();
    const userInfoCache2 = getUserInfo();
    if (userInfoCache2) {
      return {
        uid: userInfoCache2.uid,
        region: region || userInfoCache2.region
      };
    }
    throw new Error("❌ 未提供 UID 且无法从缓存获取用户信息,请确保已登录米游社");
  }
  async function processBatches(items, batchSize, processor) {
    if (items.length <= batchSize) {
      return processor(items);
    }
    const batches = [];
    for (let i = 0; i < items.length; i += batchSize) {
      batches.push(items.slice(i, i + batchSize));
    }
    const batchPromises = batches.map((batch) => processor(batch));
    const batchResults = await Promise.all(batchPromises);
    return batchResults.flat();
  }
  async function getAvatarBasicList(uid, region) {
    const userInfo = await resolveUserInfo(uid, region);
    const response = await request("/user/avatar_basic_list", NAP_CULTIVATE_TOOL_URL, {
      method: "GET",
      params: { uid: userInfo.uid, region: userInfo.region }
    });
    return response.data.list.filter((avatar) => avatar.unlocked === true);
  }
  async function batchGetAvatarDetail(avatarList, uid, region) {
    const userInfo = await resolveUserInfo(uid, region);
    const processedAvatarList = typeof avatarList[0] === "number" ? avatarList.map((id) => ({
      avatar_id: id,
      is_teaser: false,
      teaser_need_weapon: false,
      teaser_sp_skill: false
    })) : avatarList;
    return processBatches(
      processedAvatarList,
      10,
      async (batch) => {
        const response = await request("/user/batch_avatar_detail_v2", NAP_CULTIVATE_TOOL_URL, {
          method: "POST",
          params: { uid: userInfo.uid, region: userInfo.region },
          body: { avatar_list: batch }
        });
        return response.data.list;
      }
    );
  }
  async function getGameNote(roleId, server) {
    const userInfo = await resolveUserInfo(roleId, server);
    const response = await request("/note", GAME_RECORD_URL, {
      method: "GET",
      params: {
        server: userInfo.region,
        role_id: userInfo.uid
      }
    });
    return response.data;
  }
  class SeelieDataUpdater {
    static SEELIE_BASE_URL = "https://zzz.seelie.me";
    static UNIQUE_ZZZ_KEYS = ["denny", "w_engine", "drive_disc"];
    static STATS_FILE_PATTERNS = [
      { name: "charactersStats", pattern: /stats-characters-[a-f0-9]+\.js/ },
      { name: "weaponsStats", pattern: /stats-weapons-[a-f0-9]+\.js/ },
      { name: "weaponsStatsCommon", pattern: /stats-weapons-common-[a-f0-9]+\.js/ }
    ];
    /**
     * 获取网络内容
     */
    static async fetchContent(url) {
      try {
        const response = await GM_fetch(url);
        if (!response.ok) {
          throw new Error(`请求失败,状态码: ${response.status} - ${response.statusText}`);
        }
        return await response.text();
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        throw new Error(`获取 ${url} 时网络错误: ${errorMessage}`);
      }
    }
    /**
     * 从 JS 内容中还原绝区零数据
     */
    static restoreZzzData(jsContent) {
      logger.debug("▶️  开始从 JS 内容中还原绝区零数据...");
      const exportMatch = jsContent.match(/\bexport\s*\{([\s\S]*?)\}/);
      if (!exportMatch) {
        throw new Error("在JS文件中未找到 export 语句。");
      }
      const exportedVars = exportMatch[1].split(",").map((s) => s.trim().split(/\s+as\s+/)[0]).filter(Boolean);
      let executionCode = jsContent.replace(/\bexport\s*\{[\s\S]*?};/, "");
      executionCode += `

// Appended by script
return { ${exportedVars.map((v) => `${v}: ${v}`).join(", ")} };`;
      try {
        const scriptRunner = new Function(executionCode);
        const allDataBlocks = scriptRunner();
        logger.debug(`🔍 正在 ${Object.keys(allDataBlocks).length} 个数据块中搜索绝区零数据...`);
        for (const blockName in allDataBlocks) {
          const block = allDataBlocks[blockName];
          if (!block || typeof block !== "object") continue;
          const sources = [block.default, block];
          for (const source of sources) {
            if (source && typeof source === "object" && this.UNIQUE_ZZZ_KEYS.some((key) => key in source)) {
              logger.debug(`🎯 命中!在变量 '${blockName}' 中找到关键词。`);
              return source;
            }
          }
        }
        throw new Error("未能在任何数据块中找到绝区零的锚点关键词。");
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        throw new Error(`还原数据时发生错误: ${errorMessage}`);
      }
    }
    /**
     * 解析统计数据 JS 文件
     */
    static parseStatsFile(jsContent) {
      try {
        const exportMatch = jsContent.match(/\bexport\s*\{([\s\S]*?)\}/);
        if (!exportMatch) {
          throw new Error("在统计文件中未找到 export 语句");
        }
        const exportItems = exportMatch[1].split(",").map((s) => s.trim());
        const exportMappings = {};
        let defaultExportVar = null;
        exportItems.forEach((item) => {
          const parts = item.split(/\s+as\s+/);
          if (parts.length === 2) {
            const [varName, exportName] = parts;
            if (exportName.trim() === "default") {
              defaultExportVar = varName.trim();
            }
            exportMappings[exportName.trim()] = varName.trim();
          } else {
            const varName = item.trim();
            exportMappings[varName] = varName;
          }
        });
        let executionCode = jsContent.replace(/\bexport\s*\{[\s\S]*?};/, "");
        if (defaultExportVar) {
          executionCode += `

// Appended by script
return ${defaultExportVar};`;
        } else {
          const allVars = Object.values(exportMappings);
          executionCode += `

// Appended by script
return { ${allVars.map((v) => `${v}: ${v}`).join(", ")} };`;
        }
        const scriptRunner = new Function(executionCode);
        return scriptRunner();
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        throw new Error(`解析统计文件时发生错误: ${errorMessage}`);
      }
    }
    /**
     * 处理统计数据文件(并行版本)
     */
    static async processStatsFiles(indexScriptContent) {
      logger.debug("▶️  开始并行处理统计数据文件...");
      const statsPromises = this.STATS_FILE_PATTERNS.map(async ({ name, pattern }) => {
        const match = indexScriptContent.match(pattern);
        if (!match) {
          logger.warn(`⚠️  未找到 ${name} 文件,跳过...`);
          return { name, data: null };
        }
        const fileName = match[0];
        const statsFileUrl = `${this.SEELIE_BASE_URL}/assets/${fileName}`;
        logger.debug(`📥 下载 ${name} -> ${statsFileUrl}`);
        try {
          const statsFileContent = await this.fetchContent(statsFileUrl);
          const parsedData = this.parseStatsFile(statsFileContent);
          logger.debug(`✅ ${name} 处理完成`);
          return { name, data: parsedData };
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : String(error);
          logger.error(`❌ 处理 ${name} 时出错: ${errorMessage}`);
          return { name, data: null };
        }
      });
      const results = await Promise.all(statsPromises);
      const statsData = {};
      results.forEach(({ name, data }) => {
        if (data !== null) {
          statsData[name] = data;
        }
      });
      logger.debug(`✅ 统计数据并行处理完成,共处理 ${Object.keys(statsData).length} 个文件`);
      return statsData;
    }
    /**
     * 更新 Seelie 数据(优化并行版本)
     */
    static async updateSeelieData() {
      try {
        logger.debug("🚀 开始更新 Seelie 数据...");
        logger.debug("第一步:获取 Seelie.me 主页...");
        const mainPageHtml = await this.fetchContent(this.SEELIE_BASE_URL);
        const indexScriptMatch = mainPageHtml.match(/\/assets\/index-([a-f0-9]+)\.js/);
        if (!indexScriptMatch) {
          throw new Error("在主页HTML中未找到 index-....js 脚本。");
        }
        const indexScriptUrl = `${this.SEELIE_BASE_URL}${indexScriptMatch[0]}`;
        logger.debug(`第二步:发现主脚本 -> ${indexScriptUrl}`);
        const indexScriptContent = await this.fetchContent(indexScriptUrl);
        const stringsFileMatch = indexScriptContent.match(/strings-zh-([a-f0-9]+)\.js/);
        if (!stringsFileMatch) {
          throw new Error("在主脚本中未找到 strings-zh-....js 语言包。");
        }
        const stringsFileUrl = `${this.SEELIE_BASE_URL}/assets/locale/${stringsFileMatch[0]}`;
        logger.debug(`第三步:发现中文语言包 -> ${stringsFileUrl}`);
        logger.debug("🔄 开始并行处理语言包和统计数据...");
        const [stringsFileContent, statsData] = await Promise.all([
          this.fetchContent(stringsFileUrl),
          this.processStatsFiles(indexScriptContent)
        ]);
        logger.debug("✅ 语言包和统计数据并行处理完成");
        const languageData = this.restoreZzzData(stringsFileContent);
        logger.debug("🎉 Seelie 数据更新完成!");
        return { languageData, statsData };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        logger.error(`❌ Seelie 数据更新失败: ${errorMessage}`);
        throw error;
      }
    }
    /**
     * 缓存数据到 localStorage
     */
    static cacheData(languageData, statsData) {
      try {
        localStorage.setItem("seelie_language_data", JSON.stringify(languageData));
        localStorage.setItem("seelie_stats_data", JSON.stringify(statsData));
        localStorage.setItem("seelie_data_timestamp", Date.now().toString());
        logger.debug("✅ 数据已缓存到 localStorage");
      } catch (error) {
        logger.error("❌ 缓存数据失败:", error);
      }
    }
    /**
     * 从缓存获取数据
     */
    static getCachedData() {
      try {
        const languageDataStr = localStorage.getItem("seelie_language_data");
        const statsDataStr = localStorage.getItem("seelie_stats_data");
        const timestampStr = localStorage.getItem("seelie_data_timestamp");
        if (!languageDataStr || !statsDataStr || !timestampStr) {
          return null;
        }
        return {
          languageData: JSON.parse(languageDataStr),
          statsData: JSON.parse(statsDataStr),
          timestamp: parseInt(timestampStr)
        };
      } catch (error) {
        logger.error("❌ 获取缓存数据失败:", error);
        return null;
      }
    }
    /**
     * 获取最新数据(优先网络请求,失败时使用缓存)
     */
    static async getLatestData() {
      try {
        logger.debug("🔄 请求最新 Seelie 数据...");
        const { languageData, statsData } = await this.updateSeelieData();
        this.cacheData(languageData, statsData);
        return { languageData, statsData };
      } catch (error) {
        logger.warn("⚠️ 网络请求失败,尝试使用缓存数据:", error);
        const cachedData = this.getCachedData();
        if (cachedData) {
          logger.debug("✅ 使用缓存的 Seelie 数据");
          return {
            languageData: cachedData.languageData,
            statsData: cachedData.statsData
          };
        }
        throw new Error("网络请求失败且无可用缓存数据");
      }
    }
  }
  const ASCENSIONS = [1, 10, 20, 30, 40, 50, 60];
  const SKILLS = {
    0: "basic",
    // 普通攻击
    1: "special",
    // 特殊技
    2: "dodge",
    // 闪避
    3: "chain",
    // 连携技
    5: "core",
    // 核心被动
    6: "assist"
    // 支援技
  };
  const RESIN_INTERVAL = 360;
  let runtimeDataCache = {};
  async function lazyLoadSeelieData() {
    if (runtimeDataCache.loaded) {
      return;
    }
    if (runtimeDataCache.loading) {
      await runtimeDataCache.loading;
      return;
    }
    runtimeDataCache.loading = (async () => {
      try {
        logger.debug("🔄 懒加载 Seelie 数据...");
        const { languageData, statsData } = await SeelieDataUpdater.getLatestData();
        runtimeDataCache.languageData = languageData;
        runtimeDataCache.statsData = statsData;
        runtimeDataCache.loaded = true;
        logger.info("✅ Seelie 数据加载完成");
      } catch (error) {
        logger.error("❌ Seelie 数据加载失败:", error);
        throw error;
      } finally {
        runtimeDataCache.loading = void 0;
      }
    })();
    await runtimeDataCache.loading;
  }
  async function getLanguageData() {
    await lazyLoadSeelieData();
    return runtimeDataCache.languageData;
  }
  async function getStatsData() {
    await lazyLoadSeelieData();
    return runtimeDataCache.statsData;
  }
  async function getCharacterStats() {
    try {
      const statsData = await getStatsData();
      if (statsData?.charactersStats && Array.isArray(statsData.charactersStats)) {
        logger.debug("✅ 使用动态角色统计数据");
        return statsData.charactersStats;
      }
    } catch (error) {
      logger.warn("⚠️ 获取角色统计数据失败:", error);
    }
    throw new Error("无法获取角色统计数据");
  }
  async function getWeaponStats() {
    try {
      const statsData = await getStatsData();
      if (statsData?.weaponsStats && typeof statsData.weaponsStats === "object") {
        logger.debug("✅ 使用动态武器统计数据");
        return statsData.weaponsStats;
      }
    } catch (error) {
      logger.warn("⚠️ 获取武器统计数据失败:", error);
    }
    throw new Error("无法获取武器统计数据");
  }
  async function getWeaponStatsCommon() {
    try {
      const statsData = await getStatsData();
      if (statsData?.weaponsStatsCommon && typeof statsData.weaponsStatsCommon === "object") {
        logger.debug("✅ 使用动态武器通用统计数据");
        return statsData.weaponsStatsCommon;
      }
    } catch (error) {
      logger.warn("⚠️ 获取武器通用统计数据失败:", error);
    }
    throw new Error("无法获取武器通用统计数据");
  }
  class SeelieCore {
    appElement = null;
    rootComponent = null;
    constructor() {
      this.init();
    }
    /**
     * 初始化,获取 #app 元素和根组件
     */
    init() {
      this.appElement = document.querySelector("#app");
      if (!this.appElement) {
        logger.warn("⚠️ SeelieCore: 未找到 #app 元素");
        return;
      }
      if (this.appElement._vnode?.component) {
        this.completeInit();
        return;
      }
      this.waitForVNodeComponent();
    }
    /**
     * 等待 _vnode.component 出现
     */
    waitForVNodeComponent() {
      const timeoutValue = 3e3;
      if (!this.appElement) return;
      logger.debug("🔍 SeelieCore: 等待 _vnode.component 出现...", this.appElement?._vnode?.component);
      const observer = new MutationObserver(() => {
        logger.debug("🔍 SeelieCore: 等待 _vnode.component 出现...", this.appElement?._vnode?.component);
        if (this.appElement?._vnode?.component) {
          clean();
          this.completeInit();
        }
      });
      observer.observe(this.appElement, {
        attributes: true,
        childList: false,
        subtree: false
      });
      const timeoutTimer = setTimeout(() => {
        if (!this.rootComponent) {
          clean();
          logger.warn(`⚠️ SeelieCore: 等待 _vnode.component 超时 ${timeoutValue / 1e3}秒`);
        }
      }, timeoutValue);
      const clean = () => {
        observer.disconnect();
        clearTimeout(timeoutTimer);
      };
    }
    /**
     * 完成初始化
     */
    completeInit() {
      if (!this.appElement?._vnode?.component) {
        logger.warn("⚠️ SeelieCore: 完成初始化时 _vnode.component 不存在");
        return;
      }
      this.rootComponent = this.appElement._vnode.component;
      lazyLoadSeelieData();
      logger.debug("✅ SeelieCore: 已尝试初始化 stats 数据");
      logger.log("✅ SeelieCore 初始化成功");
    }
    /**
     * 确保组件已初始化
     */
    ensureInitialized() {
      if (!this.rootComponent) {
        this.init();
      }
      return !!this.rootComponent;
    }
    /**
     * 获取根组件的 proxy 对象
     */
    getProxy() {
      if (!this.ensureInitialized()) {
        return null;
      }
      return this.rootComponent?.proxy;
    }
    /**
     * 获取 accountResin 属性值
     */
    getAccountResin() {
      const proxy = this.getProxy();
      if (!proxy) {
        logger.warn("⚠️ 无法获取组件 proxy 对象");
        return null;
      }
      const accountResin = proxy.accountResin;
      logger.debug("📖 获取 accountResin:", accountResin);
      return accountResin;
    }
    /**
     * 设置 accountResin 属性值
     */
    setAccountResin(value) {
      const proxy = this.getProxy();
      if (!proxy) {
        logger.warn("⚠️ 无法获取组件 proxy 对象");
        return false;
      }
      try {
        const oldValue = proxy.accountResin;
        const convertedValue = this.convertToAccountResinFormat(value);
        proxy.accountResin = convertedValue;
        logger.debug("✏️ 设置 accountResin:", {
          oldValue,
          inputValue: value,
          convertedValue
        });
        return true;
      } catch (error) {
        logger.error("❌ 设置 accountResin 失败:", error);
        return false;
      }
    }
    /**
     * 将输入参数转换为 accountResin 格式
     */
    convertToAccountResinFormat(input) {
      if (!input || !input.progress) {
        throw new Error("输入参数格式错误,缺少 progress 字段");
      }
      const { progress, restore } = input;
      const currentAmount = progress.current;
      const maxAmount = progress.max;
      const restoreSeconds = restore;
      const now = /* @__PURE__ */ new Date();
      const theoreticalRestoreTime = (maxAmount - currentAmount) * RESIN_INTERVAL;
      const updateTime = new Date(now.getTime() + (restoreSeconds - theoreticalRestoreTime) * 1e3);
      return {
        amount: currentAmount,
        time: updateTime.toString()
      };
    }
    /**
     * 设置 Toast 消息
     */
    setToast(message, type = "") {
      const proxy = this.getProxy();
      if (!proxy) {
        logger.warn("⚠️ 无法获取组件 proxy 对象");
        return false;
      }
      try {
        proxy.toast = message;
        proxy.toastType = type;
        logger.debug("🍞 设置 Toast:", { message, type });
        return true;
      } catch (error) {
        logger.error("❌ 设置 Toast 失败:", error);
        return false;
      }
    }
    /**
     * 调用组件的 addGoal 方法
     */
    addGoal(goal) {
      const proxy = this.getProxy();
      if (!proxy) {
        logger.warn("⚠️ 无法获取组件 proxy 对象");
        return false;
      }
      if (typeof proxy.addGoal !== "function") {
        logger.warn("⚠️ addGoal 方法不存在");
        return false;
      }
      try {
        proxy.addGoal(goal);
        return true;
      } catch (error) {
        logger.error("❌ 调用 addGoal 失败:", error);
        return false;
      }
    }
    /**
     * 调用组件的 removeGoal 方法
     */
    removeGoal(goal) {
      const proxy = this.getProxy();
      if (!proxy) {
        logger.warn("⚠️ 无法获取组件 proxy 对象");
        return false;
      }
      if (typeof proxy.removeGoal !== "function") {
        logger.warn("⚠️ removeGoal 方法不存在");
        return false;
      }
      try {
        proxy.removeGoal(goal);
        return true;
      } catch (error) {
        logger.error("❌ 调用 removeGoal 失败:", error);
        return false;
      }
    }
    /**
     * 调用组件的 setInventory 方法
     */
    setInventory(type, item, tier, value) {
      const proxy = this.getProxy();
      if (!proxy) {
        logger.warn("⚠️ 无法获取组件 proxy 对象");
        return false;
      }
      if (typeof proxy.setInventory !== "function") {
        logger.warn("⚠️ setInventory 方法不存在");
        return false;
      }
      try {
        proxy.setInventory(type, item, tier, value);
        return true;
      } catch (error) {
        logger.error("❌ 调用 setInventory 失败:", error);
        return false;
      }
    }
    /**
     * 获取组件的 characters 数据
     */
    getCharacters() {
      const proxy = this.getProxy();
      return proxy?.characters || {};
    }
    /**
     * 获取组件的 weapons 数据
     */
    getWeapons() {
      const proxy = this.getProxy();
      return proxy?.weapons || {};
    }
    /**
     * 获取组件的 goals 数据
     */
    getGoals() {
      const proxy = this.getProxy();
      return proxy?.goals || [];
    }
    /**
     * 获取组件的 items 数据
     */
    getItems() {
      const proxy = this.getProxy();
      return proxy?.items || {};
    }
    /**
     * 获取完整的组件上下文信息(调试用)
     */
    getContextInfo() {
      const proxy = this.getProxy();
      if (!proxy) {
        return null;
      }
      return {
        keys: Object.keys(proxy),
        accountResin: proxy.accountResin,
        hasAccountResin: "accountResin" in proxy,
        contextType: typeof proxy
      };
    }
    /**
     * 重新初始化(当页面路由变化时调用)
     */
    refresh() {
      logger.debug("🔄 SeelieCore 重新初始化...");
      this.appElement = null;
      this.rootComponent = null;
      this.init();
    }
  }
  async function calculateCharacterAsc(character) {
    try {
      const characterStats = await getCharacterStats();
      const stats = characterStats.find((s) => s.id === character.id);
      if (!stats) {
        logger.warn(`⚠️ 未找到角色 ${character.name_mi18n} 的统计数据`);
        return ASCENSIONS.findIndex((level) => level >= character.level);
      }
      const hpProperty = character.properties.find((p) => p.property_id === 1);
      if (!hpProperty) {
        logger.warn(`⚠️ 角色 ${character.name_mi18n} 缺少生命值属性`);
        return ASCENSIONS.findIndex((level) => level >= character.level);
      }
      const actualHP = parseInt(hpProperty.base || hpProperty.final);
      const baseHP = stats.base;
      const growthHP = (character.level - 1) * stats.growth / 1e4;
      const coreSkill = character.skills.find((s) => s.skill_type === 5);
      const coreHP = coreSkill && stats.core ? stats.core[coreSkill.level - 2] || 0 : 0;
      const calculatedBaseHP = baseHP + growthHP + coreHP;
      for (let i = 0; i < stats.ascHP.length; i++) {
        const ascHP = stats.ascHP[i];
        if (Math.floor(calculatedBaseHP + ascHP) === actualHP) {
          return i;
        }
      }
      logger.debug(`HP error: ${character.name_mi18n}, base: ${baseHP}, growth: ${growthHP}, core: ${coreHP}, fixed: ${calculatedBaseHP}, target: ${actualHP}`);
      return ASCENSIONS.findIndex((level) => level >= character.level);
    } catch (error) {
      logger.error("❌ 计算角色突破等级失败:", error);
      return ASCENSIONS.findIndex((level) => level >= character.level);
    }
  }
  async function calculateWeaponAsc(weapon) {
    try {
      const weaponStatsCommon = await getWeaponStatsCommon();
      const weaponStats = await getWeaponStats();
      const levelRate = weaponStatsCommon.rate[weapon.level] || 0;
      const atkProperty = weapon.main_properties.find((p) => p.property_id === 12101);
      if (!atkProperty) {
        logger.warn(`⚠️ 武器 ${weapon.name} 缺少攻击力属性`);
        return ASCENSIONS.findIndex((level) => level >= weapon.level);
      }
      const actualATK = parseInt(atkProperty.base);
      const baseATK = weaponStats[weapon.id] || 48;
      const growthATK = baseATK * levelRate / 1e4;
      const calculatedBaseATK = baseATK + growthATK;
      for (let i = 0; i < weaponStatsCommon.ascRate.length; i++) {
        const ascRate = weaponStatsCommon.ascRate[i];
        const ascATK = baseATK * ascRate / 1e4;
        if (Math.floor(calculatedBaseATK + ascATK) === actualATK) {
          return i;
        }
      }
      logger.debug(`ATK error: ${weapon.name}, base: ${baseATK}, growth: ${growthATK}, fixed: ${calculatedBaseATK}, target: ${actualATK}`);
      return ASCENSIONS.findIndex((level) => level >= weapon.level);
    } catch (error) {
      logger.error("❌ 计算武器突破等级失败:", error);
      return ASCENSIONS.findIndex((level) => level >= weapon.level);
    }
  }
  function calculateSkillLevel(skillLevel, skillType, characterRank) {
    let currentLevel = skillLevel;
    if (skillType === "core") {
      currentLevel--;
    } else if (characterRank >= 5) {
      currentLevel -= 4;
    } else if (characterRank >= 3) {
      currentLevel -= 2;
    }
    return Math.max(1, currentLevel);
  }
  class CharacterManager extends SeelieCore {
    /**
     * 设置角色基础数据
     */
    async setCharacter(data) {
      try {
        const character = data.avatar || data;
        const characterKey = this.findCharacterKey(character.id);
        if (!characterKey) {
          throw new Error("Character not found.");
        }
        const existingGoal = this.findExistingGoal(characterKey, "character");
        const currentAsc = await calculateCharacterAsc(character);
        const existingGoalData = existingGoal;
        let targetLevel = existingGoalData?.goal?.level;
        if (!targetLevel || targetLevel < character.level) {
          targetLevel = character.level;
        }
        let targetAsc = existingGoalData?.goal?.asc;
        if (!targetAsc || targetAsc < currentAsc) {
          targetAsc = currentAsc;
        }
        const goal = {
          type: "character",
          character: characterKey,
          cons: character.rank,
          current: {
            level: character.level,
            asc: currentAsc
          },
          goal: {
            level: targetLevel || character.level,
            asc: targetAsc || currentAsc
          }
        };
        if (this.addGoal(goal)) {
          logger.debug("✓ 角色数据设置成功:", {
            character: characterKey,
            level: character.level,
            rank: character.rank,
            currentAsc,
            targetLevel,
            targetAsc
          });
          return true;
        }
        return false;
      } catch (error) {
        logger.error("❌ 设置角色数据失败:", error);
        return false;
      }
    }
    /**
     * 设置角色天赋数据
     */
    setTalents(data) {
      try {
        const character = data.avatar || data;
        const characterKey = this.findCharacterKey(character.id);
        if (!characterKey) {
          throw new Error("Character not found.");
        }
        const existingGoal = this.findExistingGoal(characterKey, "talent");
        const talents = {};
        character.skills.forEach((skill) => {
          const skillType = SKILLS[skill.skill_type];
          if (!skillType) return;
          const currentLevel = calculateSkillLevel(skill.level, skillType, character.rank);
          const existingSkillGoal = existingGoal;
          let targetLevel = existingSkillGoal?.[skillType]?.goal;
          if (!targetLevel || targetLevel < currentLevel) {
            targetLevel = currentLevel;
          }
          talents[skillType] = {
            current: currentLevel,
            goal: targetLevel || currentLevel
          };
        });
        const goal = {
          type: "talent",
          character: characterKey,
          ...talents
        };
        if (this.addGoal(goal)) {
          logger.debug("✓ 角色天赋数据设置成功:", { character: characterKey, talents });
          return true;
        }
        return false;
      } catch (error) {
        logger.error("❌ 设置角色天赋数据失败:", error);
        return false;
      }
    }
    /**
     * 设置武器数据
     */
    async setWeapon(data) {
      try {
        const character = data.avatar || data;
        const weapon = data.weapon;
        const characterKey = this.findCharacterKey(character.id);
        if (!characterKey) {
          throw new Error("Character not found.");
        }
        const existingGoal = this.findExistingGoal(characterKey, "weapon");
        if (!weapon) {
          if (existingGoal && this.removeGoal(existingGoal)) {
            logger.debug("✓ 移除武器目标成功");
          }
          return true;
        }
        const weaponKey = this.findWeaponKey(weapon.id);
        if (!weaponKey) {
          throw new Error("Weapon not found.");
        }
        const currentAsc = await calculateWeaponAsc(weapon);
        const current = {
          level: weapon.level,
          asc: currentAsc
        };
        let goal = {
          level: current.level,
          asc: current.asc
        };
        const weapons = this.getWeapons();
        const existingGoalData = existingGoal;
        const existingWeapon = existingGoalData?.weapon ? weapons[existingGoalData.weapon] : null;
        const newWeapon = weapons[weaponKey];
        if (existingWeapon?.id === newWeapon?.id && existingGoalData?.goal) {
          goal.level = Math.max(existingGoalData.goal.level || current.level, current.level);
          goal.asc = Math.max(existingGoalData.goal.asc || current.asc, current.asc);
          if (newWeapon.craftable) {
            current.craft = weapon.star;
            goal.craft = Math.max(existingGoalData.goal.craft || weapon.star, weapon.star);
          }
        } else {
          if (newWeapon.craftable) {
            current.craft = weapon.star;
            goal.craft = weapon.star;
          }
        }
        const weaponGoal = {
          type: "weapon",
          character: characterKey,
          weapon: weaponKey,
          current,
          goal
        };
        if (this.addGoal(weaponGoal)) {
          logger.debug("✓ 武器数据设置成功:", {
            character: characterKey,
            weapon: weaponKey,
            current,
            goal
          });
          return true;
        }
        return false;
      } catch (error) {
        logger.error("❌ 设置武器数据失败:", error);
        return false;
      }
    }
    /**
     * 同步单个角色的完整数据
     */
    async syncCharacter(data) {
      const result = {
        success: 0,
        failed: 0,
        errors: []
      };
      const character = data.avatar || data;
      const characterName = character.name_mi18n || `角色ID:${character.id}`;
      logger.debug(`🔄 开始同步角色: ${characterName}`);
      const operations = [
        { name: "角色数据", fn: () => this.setCharacter(data) },
        { name: "天赋数据", fn: () => this.setTalents(data) },
        { name: "武器数据", fn: () => this.setWeapon(data) }
      ];
      const operationPromises = operations.map(async ({ name, fn }) => {
        try {
          const success = await fn();
          if (success) {
            logger.debug(`✓ ${characterName} - ${name}同步成功`);
            return { success: true, error: null };
          } else {
            const errorMsg = `${characterName} - ${name}同步失败`;
            return { success: false, error: errorMsg };
          }
        } catch (error) {
          const errorMsg = `${characterName} - ${name}同步错误: ${error}`;
          logger.error(`❌ ${errorMsg}`);
          return { success: false, error: errorMsg };
        }
      });
      const results = await Promise.all(operationPromises);
      results.forEach(({ success, error }) => {
        if (success) {
          result.success++;
        } else {
          result.failed++;
          if (error) {
            result.errors.push(error);
          }
        }
      });
      logger.debug(`✅ ${characterName} 同步完成 - 成功: ${result.success}, 失败: ${result.failed}`);
      return result;
    }
    /**
     * 同步多个角色的完整数据
     */
    async syncAllCharacters(dataList) {
      const overallResult = {
        total: dataList.length,
        success: 0,
        failed: 0,
        errors: [],
        details: []
      };
      logger.debug(`🚀 开始批量同步 ${dataList.length} 个角色`);
      const syncPromises = dataList.map(async (data, index) => {
        const character = data.avatar || data;
        const characterName = character.name_mi18n || `角色ID:${character.id}`;
        logger.debug(`📝 [${index + 1}/${dataList.length}] 同步角色: ${characterName}`);
        try {
          const result = await this.syncCharacter(data);
          return {
            character: characterName,
            result,
            success: result.failed === 0
          };
        } catch (error) {
          const errorMsg = `${characterName} - 批量同步失败: ${error}`;
          logger.error(`❌ ${errorMsg}`);
          return {
            character: characterName,
            result: { success: 0, failed: 1, errors: [errorMsg] },
            success: false
          };
        }
      });
      const results = await Promise.all(syncPromises);
      results.forEach(({ character, result, success }) => {
        overallResult.details.push({
          character,
          result
        });
        if (success) {
          overallResult.success++;
        } else {
          overallResult.failed++;
          overallResult.errors.push(...result.errors);
        }
      });
      this.logBatchResult(overallResult);
      return overallResult;
    }
    /**
     * 查找角色键名
     */
    findCharacterKey(characterId) {
      const characters = this.getCharacters();
      return Object.keys(characters).find((key) => characters[key].id === characterId) || null;
    }
    /**
     * 查找武器键名
     */
    findWeaponKey(weaponId) {
      const weapons = this.getWeapons();
      return Object.keys(weapons).find((key) => weapons[key].id === weaponId) || null;
    }
    /**
     * 查找现有目标
     */
    findExistingGoal(characterKey, type) {
      const goals = this.getGoals();
      return goals.find((goal) => {
        const g = goal;
        return g.character === characterKey && g.type === type;
      });
    }
    /**
     * 记录批量同步结果
     */
    logBatchResult(result) {
      logger.debug(`🎯 批量同步完成:`);
      logger.debug(`   总计: ${result.total} 个角色`);
      logger.debug(`   成功: ${result.success} 个角色`);
      logger.debug(`   失败: ${result.failed} 个角色`);
      if (result.errors.length > 0) {
        logger.debug(`   错误详情:`);
        result.errors.forEach((error) => logger.debug(`     - ${error}`));
      }
    }
    /**
     * 显示批量同步 Toast
     */
    // private showBatchToast(result: BatchSyncResult): void {
    //   if (result.success > 0) {
    //     this.setToast(
    //       `成功同步 ${result.success}/${result.total} 个角色`,
    //       result.failed === 0 ? 'success' : 'warning'
    //     )
    //   }
    //   if (result.failed > 0) {
    //     this.setToast(
    //       `${result.failed} 个角色同步失败,请查看控制台`,
    //       'error'
    //     )
    //   }
    // }
    // 辅助函数
    // 缓存变量
    _minimumSetCoverCache = null;
    _minimumSetWeaponsCache = null;
    /**
     * 使用贪心算法找到最小集合覆盖的角色ID列表
     * 目标是用最少的角色覆盖所有属性组合(属性、风格、模拟材料、周本)
     */
    findMinimumSetCoverIds() {
      if (this._minimumSetCoverCache !== null) {
        logger.debug("📦 使用缓存的最小集合覆盖结果");
        return this._minimumSetCoverCache;
      }
      const charactersData = this.getCharacters();
      const charactersArray = Object.values(charactersData);
      const universeOfAttributes = /* @__PURE__ */ new Set();
      for (const char of charactersArray) {
        universeOfAttributes.add(char.attribute);
        universeOfAttributes.add(char.style);
        universeOfAttributes.add(char.boss);
        universeOfAttributes.add(char.boss_weekly);
      }
      const attributesToCover = new Set(universeOfAttributes);
      const resultIds = [];
      const usedCharacterIds = /* @__PURE__ */ new Set();
      while (attributesToCover.size > 0) {
        let bestCharacter = null;
        let maxCoveredCount = 0;
        for (const char of charactersArray) {
          if (usedCharacterIds.has(char.id)) {
            continue;
          }
          if (new Date(char.release) > /* @__PURE__ */ new Date()) {
            continue;
          }
          const characterAttributes = /* @__PURE__ */ new Set([
            char.attribute,
            char.style,
            char.boss,
            char.boss_weekly
          ]);
          let currentCoverCount = 0;
          for (const attr of characterAttributes) {
            if (attributesToCover.has(attr)) {
              currentCoverCount++;
            }
          }
          if (currentCoverCount > maxCoveredCount) {
            maxCoveredCount = currentCoverCount;
            bestCharacter = char;
          }
        }
        if (bestCharacter === null) {
          logger.warn("⚠️ 无法覆盖所有属性,可能缺少某些属性的组合");
          break;
        }
        resultIds.push({ id: bestCharacter.id, style: bestCharacter.style });
        usedCharacterIds.add(bestCharacter.id);
        const bestCharacterAttributes = /* @__PURE__ */ new Set([
          bestCharacter.attribute,
          bestCharacter.style,
          bestCharacter.boss,
          bestCharacter.boss_weekly
        ]);
        for (const attr of bestCharacterAttributes) {
          attributesToCover.delete(attr);
        }
        logger.debug(`✅ 选择角色 ${bestCharacter.id},覆盖 ${maxCoveredCount} 个属性`);
      }
      logger.debug(`🎯 最小集合覆盖完成,共选择 ${resultIds.length} 个角色: ${resultIds.join(", ")}`);
      this._minimumSetCoverCache = resultIds;
      return resultIds;
    }
    /**
     * 返回每个职业对应一个武器
     */
    findMinimumSetWeapons() {
      if (this._minimumSetWeaponsCache !== null) {
        logger.debug("📦 使用缓存的最小武器集合结果");
        return this._minimumSetWeaponsCache;
      }
      const weaponsData = this.getWeapons();
      const weaponsArray = Object.values(weaponsData);
      const result = {};
      for (const weapon of weaponsArray) {
        if (weapon.tier === 5 && !result[weapon.style] && /* @__PURE__ */ new Date() >= new Date(weapon.release)) {
          result[weapon.style] = weapon.id;
        }
      }
      this._minimumSetWeaponsCache = result;
      return result;
    }
  }
  class SeelieDataManager extends CharacterManager {
    // 继承所有功能,无需额外实现
  }
  const seelieDataManager = new SeelieDataManager();
  const setResinData = (data) => {
    return seelieDataManager.setAccountResin(data);
  };
  const setToast = (message, type = "success") => {
    return seelieDataManager.setToast(message, type);
  };
  const syncCharacter = async (data) => {
    return await seelieDataManager.syncCharacter(data);
  };
  const syncAllCharacters$1 = async (dataList) => {
    return await seelieDataManager.syncAllCharacters(dataList);
  };
  const setInventory = (type, item, tier, value) => {
    return seelieDataManager.setInventory(type, item, tier, value);
  };
  const findMinimumSetCoverIds = () => {
    return seelieDataManager.findMinimumSetCoverIds();
  };
  const findMinimumSetWeapons = () => {
    return seelieDataManager.findMinimumSetWeapons();
  };
  const getItems = () => {
    return seelieDataManager.getItems();
  };
  var SkillType = /* @__PURE__ */ ((SkillType2) => {
    SkillType2[SkillType2["NormalAttack"] = 0] = "NormalAttack";
    SkillType2[SkillType2["SpecialSkill"] = 1] = "SpecialSkill";
    SkillType2[SkillType2["Dodge"] = 2] = "Dodge";
    SkillType2[SkillType2["Chain"] = 3] = "Chain";
    SkillType2[SkillType2["CorePassive"] = 5] = "CorePassive";
    SkillType2[SkillType2["SupportSkill"] = 6] = "SupportSkill";
    return SkillType2;
  })(SkillType || {});
  async function getAvatarItemCalc(avatar_id, weapon_id, uid, region) {
    const userInfo = await resolveUserInfo(uid, region);
    const body = {
      avatar_id: Number(avatar_id),
      avatar_level: ASCENSIONS[ASCENSIONS.length - 1],
      // 最大等级
      avatar_current_level: 1,
      avatar_current_promotes: 1,
      skills: Object.values(SkillType).filter((value) => typeof value !== "string").map((skillType) => ({
        skill_type: skillType,
        level: skillType === SkillType.CorePassive ? 7 : 12,
        init_level: 1
        // 初始
      })),
      weapon_info: {
        weapon_id: Number(weapon_id),
        weapon_level: ASCENSIONS[ASCENSIONS.length - 1],
        weapon_promotes: 0,
        weapon_init_level: 0
      }
    };
    const response = await request("/user/avatar_calc", NAP_CULTIVATE_TOOL_URL, {
      method: "POST",
      params: { uid: userInfo.uid, region: userInfo.region },
      body
    });
    return response.data;
  }
  async function batchGetAvatarItemCalc(calcAvatars, uid, region) {
    const promises = calcAvatars.map(
      (item) => getAvatarItemCalc(item.avatar_id, item.weapon_id, uid, region)
    );
    return await Promise.all(promises);
  }
  class SyncService {
    /**
     * 同步电量(树脂)数据
     */
    async syncResinData() {
      try {
        logger.debug("🔋 开始同步电量数据...");
        const gameNote = await getGameNote();
        if (!gameNote) {
          logger.error("❌ 获取游戏便笺失败");
          setToast("获取游戏便笺失败", "error");
          return false;
        }
        const resinData = gameNote.energy;
        const success = setResinData(resinData);
        if (success) {
          logger.debug("✅ 电量数据同步成功");
          setToast(`电量同步成功: ${resinData.progress.current}/${resinData.progress.max}`, "success");
        } else {
          logger.error("❌ 电量数据设置失败");
          setToast("电量数据设置失败", "error");
        }
        return success;
      } catch (error) {
        logger.error("❌ 电量数据同步失败:", error);
        setToast("电量数据同步失败", "error");
        return false;
      }
    }
    /**
     * 同步单个角色数据
     */
    async syncSingleCharacter(avatarId) {
      try {
        logger.debug(`👤 开始同步角色数据: ${avatarId}`);
        const avatarDetails = await batchGetAvatarDetail([avatarId], void 0);
        if (!avatarDetails || avatarDetails.length === 0) {
          const message = "获取角色详细信息失败";
          logger.error(`❌ ${message}`);
          setToast(message, "error");
          return { success: 0, failed: 1, errors: [message] };
        }
        const avatarDetail = avatarDetails[0];
        const result = await syncCharacter(avatarDetail);
        if (result.success > 0) {
          logger.debug(`✅ 角色 ${avatarDetail.avatar.name_mi18n} 同步成功`);
          setToast(`角色 ${avatarDetail.avatar.name_mi18n} 同步成功`, "success");
        } else {
          logger.error(`❌ 角色 ${avatarDetail.avatar.name_mi18n} 同步失败`);
          setToast(`角色 ${avatarDetail.avatar.name_mi18n} 同步失败`, "error");
        }
        return result;
      } catch (error) {
        const message = `角色 ${avatarId} 同步失败`;
        logger.error(`❌ ${message}:`, error);
        setToast(message, "error");
        return { success: 0, failed: 1, errors: [String(error)] };
      }
    }
    /**
     * 同步所有角色数据
     */
    async syncAllCharacters() {
      try {
        logger.debug("👥 开始同步所有角色数据...");
        const avatarList = await getAvatarBasicList();
        if (!avatarList || avatarList.length === 0) {
          const message = "获取角色列表失败或角色列表为空";
          logger.error(`❌ ${message}`);
          setToast(message, "error");
          return {
            success: 0,
            failed: 1,
            errors: [message],
            total: 0,
            details: []
          };
        }
        logger.debug(`📋 找到 ${avatarList.length} 个角色`);
        setToast(`开始同步 ${avatarList.length} 个角色...`, "");
        const avatarIds = avatarList.map((avatar) => avatar.avatar.id);
        const avatarDetails = await batchGetAvatarDetail(avatarIds, void 0);
        if (!avatarDetails || avatarDetails.length === 0) {
          const message = "获取角色详细信息失败";
          logger.error(`❌ ${message}`);
          setToast(message, "error");
          return {
            success: 0,
            failed: 1,
            errors: [message],
            total: 0,
            details: []
          };
        }
        const batchResult = await syncAllCharacters$1(avatarDetails);
        if (batchResult.success > 0) {
          logger.debug(`✅ 所有角色同步完成: 成功 ${batchResult.success},失败 ${batchResult.failed}`);
          setToast(`角色同步完成: 成功 ${batchResult.success},失败 ${batchResult.failed}`, "success");
        } else {
          logger.error(`❌ 角色批量同步失败`);
          setToast("角色批量同步失败", "error");
        }
        return batchResult;
      } catch (error) {
        const message = "所有角色同步失败";
        logger.error(`❌ ${message}:`, error);
        setToast(message, "error");
        return {
          success: 0,
          failed: 1,
          errors: [String(error)],
          total: 0,
          details: []
        };
      }
    }
    /**
     * 同步养成材料数据
     */
    async syncItemsData() {
      try {
        logger.debug("🔋 开始始同步养成材料数据...");
        const minSetChar = findMinimumSetCoverIds();
        const minSetWeapon = findMinimumSetWeapons();
        const calcParams = minSetChar.map((item) => ({
          avatar_id: item.id,
          weapon_id: minSetWeapon[item.style]
        }));
        const itemsData = await batchGetAvatarItemCalc(calcParams);
        if (!itemsData) {
          const message = "获取养成材料数据失败";
          logger.error(`❌ ${message}`);
          setToast(message, "error");
          return false;
        }
        const allItemsInfo = this.collectAllItemsInfo(itemsData);
        const itemsInventory = this.buildItemsInventory(itemsData, allItemsInfo);
        const seelieItems = getItems();
        seelieItems["denny"] = { type: "denny" };
        const i18nData = await getLanguageData();
        if (!i18nData) {
          const message = "获取语言数据失败";
          logger.error(`❌ ${message}`);
          setToast(message, "error");
          return false;
        }
        const cnName2SeelieItemName = this.buildCnToSeelieNameMapping(i18nData);
        const { successNum, failNum } = this.syncItemsToSeelie(
          itemsInventory,
          cnName2SeelieItemName,
          seelieItems
        );
        const success = successNum > 0;
        const total = successNum + failNum;
        if (success) {
          logger.debug(`✅ 养成材料同步成功: ${successNum}/${total}`);
          const toastType = failNum === 0 ? "success" : "warning";
          setToast(`养成材料同步成功: ${successNum}/${total}`, toastType);
        } else {
          logger.error("❌ 养成材料同步失败");
          setToast("养成材料同步失败", "error");
        }
        return success;
      } catch (error) {
        const message = "养成材料同步失败";
        logger.error(`❌ ${message}:`, error);
        setToast(message, "error");
        return false;
      }
    }
    /**
     * 收集所有物品信息(从所有消耗类型中获取完整的物品信息)
     */
    collectAllItemsInfo(itemsData) {
      const allItemsInfo = {};
      for (const data of itemsData) {
        const allConsumes = [
          ...data.avatar_consume,
          ...data.weapon_consume,
          ...data.skill_consume,
          ...data.need_get
        ];
        for (const item of allConsumes) {
          const id = item.id.toString();
          if (!(id in allItemsInfo)) {
            allItemsInfo[id] = {
              id: item.id,
              name: item.name
            };
          }
        }
      }
      return allItemsInfo;
    }
    /**
     * 构建物品库存数据(名称到数量的映射)
     */
    buildItemsInventory(itemsData, allItemsInfo) {
      const inventory = {};
      const userOwnItems = {};
      for (const data of itemsData) {
        Object.assign(userOwnItems, data.user_owns_materials);
      }
      for (const [id, itemInfo] of Object.entries(allItemsInfo)) {
        const count = userOwnItems[id] || 0;
        inventory[itemInfo.name] = count;
      }
      return inventory;
    }
    /**
     * 构建中文名称到 Seelie 物品名称的映射
     */
    buildCnToSeelieNameMapping(i18nData) {
      const mapping = {};
      for (const [key, value] of Object.entries(i18nData)) {
        if (typeof value === "string") {
          mapping[value] = key;
        } else if (Array.isArray(value)) {
          value.forEach((v, index) => {
            mapping[v] = `${key}+${index}`;
          });
        }
      }
      return mapping;
    }
    /**
     * 同步物品到 Seelie
     */
    syncItemsToSeelie(itemsInventory, cnName2SeelieItemName, seelieItems) {
      let successNum = 0;
      let failNum = 0;
      for (const [cnName, count] of Object.entries(itemsInventory)) {
        const seelieName = cnName2SeelieItemName[cnName];
        if (!seelieName) {
          failNum++;
          continue;
        }
        try {
          const seelieNameParts = seelieName.split("+");
          if (seelieNameParts.length > 1) {
            const realName = seelieNameParts[0];
            const tier = Number(seelieNameParts[1]);
            const type = seelieItems[realName].type;
            if (type && setInventory(type, realName, tier, count)) {
              successNum++;
            } else {
              failNum++;
            }
          } else {
            const type = seelieItems[seelieName]?.type;
            if (type && setInventory(type, seelieName, 0, count)) {
              successNum++;
            } else {
              failNum++;
            }
          }
        } catch {
          failNum++;
        }
      }
      return { successNum, failNum };
    }
    /**
     * 执行完整同步(电量 + 所有角色 + 养成材料)
     */
    async syncAll() {
      logger.debug("🚀 开始执行完整同步...");
      setToast("开始执行完整同步...", "");
      const [resinSync, characterSync, itemsSync] = await Promise.all([
        this.syncResinData(),
        this.syncAllCharacters(),
        this.syncItemsData()
      ]);
      const totalSuccess = resinSync && characterSync.success > 0 && itemsSync;
      const message = totalSuccess ? "完整同步成功" : "完整同步部分失败";
      logger.debug(`${totalSuccess ? "✅" : "⚠️"} ${message}`);
      setToast(message, totalSuccess ? "success" : "error");
      return { resinSync, characterSync, itemsSync };
    }
  }
  const syncService = new SyncService();
  const syncResinData = () => {
    return syncService.syncResinData();
  };
  const syncAllCharacters = () => {
    return syncService.syncAllCharacters();
  };
  const syncItemsData = () => {
    return syncService.syncItemsData();
  };
  const syncAll = () => {
    return syncService.syncAll();
  };
  const MYS_URL = "https://act.mihoyo.com/zzz/gt/character-builder-h#/";
  class SeeliePanel {
    container = null;
    userInfo = null;
    isLoading = false;
    isExpanded = false;
    // 控制二级界面展开状态
    // 组件相关的选择器常量
    static TARGET_SELECTOR = "div.flex.flex-col.items-center.justify-center.w-full.mt-3";
    static PANEL_SELECTOR = '[data-seelie-panel="true"]';
    constructor() {
    }
    /**
     * 初始化面板 - 由外部调用
     */
    async init() {
      try {
        await this.createPanel();
      } catch (error) {
        logger.error("初始化 Seelie 面板失败:", error);
        throw error;
      }
    }
    /**
     * 创建面板
     */
    async createPanel() {
      const targetContainer = document.querySelector(SeeliePanel.TARGET_SELECTOR);
      if (!targetContainer) {
        throw new Error("目标容器未找到");
      }
      const existingPanel = targetContainer.querySelector(SeeliePanel.PANEL_SELECTOR);
      if (existingPanel) {
        existingPanel.remove();
        logger.debug("清理了目标容器中的旧面板");
      }
      if (this.container && targetContainer.contains(this.container)) {
        logger.debug("面板已存在,跳过创建");
        return;
      }
      await this.loadUserInfo();
      this.container = this.createPanelElement();
      targetContainer.insertBefore(this.container, targetContainer.firstChild);
      logger.info("✅ Seelie 面板创建成功");
    }
    /**
     * 加载用户信息
     */
    async loadUserInfo() {
      try {
        this.userInfo = await initializeUserInfo();
        logger.debug("用户信息加载成功:", this.userInfo);
      } catch (error) {
        logger.error("加载用户信息失败:", error);
        this.userInfo = null;
        const errorMessage = String(error);
        if (errorMessage.includes("获取用户角色失败") || errorMessage.includes("未登录") || errorMessage.includes("HTTP 401") || errorMessage.includes("HTTP 403")) {
          this.userInfo = { error: "login_required", message: "请先登录米游社账号" };
        } else if (errorMessage.includes("未找到绝区零游戏角色")) {
          this.userInfo = { error: "no_character", message: "未找到绝区零游戏角色" };
        } else if (errorMessage.includes("网络") || errorMessage.includes("timeout") || errorMessage.includes("fetch")) {
          this.userInfo = { error: "network_error", message: "网络连接失败,请重试" };
        } else {
          this.userInfo = { error: "unknown", message: "用户信息加载失败" };
        }
      }
    }
    /**
     * 创建面板元素
     */
    createPanelElement() {
      const panel = document.createElement("div");
      panel.className = "w-full mb-3 p-3 bg-gray-800 rounded-lg border border-gray-200/20";
      panel.setAttribute("data-seelie-panel", "true");
      const userInfoSection = this.createUserInfoSection();
      const syncSection = this.createSyncSection();
      panel.appendChild(userInfoSection);
      panel.appendChild(syncSection);
      return panel;
    }
    /**
     * 创建用户信息区域
     */
    createUserInfoSection() {
      const section = document.createElement("div");
      section.className = "flex flex-col items-center justify-center mb-3";
      const infoText = document.createElement("div");
      infoText.className = "flex flex-col items-center text-center";
      if (this.userInfo && !("error" in this.userInfo)) {
        const nickname = document.createElement("div");
        nickname.className = "text-sm font-medium text-white";
        nickname.textContent = this.userInfo.nickname;
        const uid = document.createElement("div");
        uid.className = "text-xs text-gray-400";
        uid.textContent = `UID: ${this.userInfo.uid}`;
        infoText.appendChild(nickname);
        infoText.appendChild(uid);
      } else if (this.userInfo && "error" in this.userInfo) {
        const errorInfo = this.userInfo;
        const errorContainer = document.createElement("div");
        errorContainer.className = "flex flex-col items-center";
        const errorIcon = document.createElement("div");
        errorIcon.className = "text-red-400 mb-2";
        errorIcon.innerHTML = `
        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
        </svg>
      `;
        const errorMessage = document.createElement("div");
        errorMessage.className = "text-sm text-red-400 mb-2";
        errorMessage.textContent = errorInfo.message;
        errorContainer.appendChild(errorIcon);
        errorContainer.appendChild(errorMessage);
        if (errorInfo.error === "login_required") {
          const loginHint = document.createElement("div");
          loginHint.className = "text-xs text-gray-400 mb-2 text-center";
          loginHint.textContent = "请在新标签页中登录米游社后刷新页面";
          const loginButton = document.createElement("button");
          loginButton.className = "px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white text-xs rounded transition-all duration-200";
          loginButton.textContent = "前往米游社登录";
          loginButton.addEventListener("click", () => {
            window.open(MYS_URL, "_blank");
          });
          errorContainer.appendChild(loginHint);
          errorContainer.appendChild(loginButton);
        } else if (errorInfo.error === "no_character") {
          const characterHint = document.createElement("div");
          characterHint.className = "text-xs text-gray-400 mb-2 text-center";
          characterHint.textContent = "请先在米游社绑定绝区零游戏角色";
          const bindButton = document.createElement("button");
          bindButton.className = "px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-xs rounded transition-all duration-200";
          bindButton.textContent = "前往绑定角色";
          bindButton.addEventListener("click", () => {
            window.open(MYS_URL, "_blank");
          });
          errorContainer.appendChild(characterHint);
          errorContainer.appendChild(bindButton);
        } else if (errorInfo.error === "network_error") {
          const retryButton = document.createElement("button");
          retryButton.className = "px-3 py-1 bg-green-600 hover:bg-green-700 text-white text-xs rounded transition-all duration-200";
          retryButton.textContent = "重试";
          retryButton.addEventListener("click", () => this.refreshUserInfo());
          errorContainer.appendChild(retryButton);
        } else {
          const retryButton = document.createElement("button");
          retryButton.className = "px-3 py-1 bg-gray-600 hover:bg-gray-700 text-white text-xs rounded transition-all duration-200";
          retryButton.textContent = "重试";
          retryButton.addEventListener("click", () => this.refreshUserInfo());
          errorContainer.appendChild(retryButton);
        }
        infoText.appendChild(errorContainer);
      } else {
        const errorText = document.createElement("div");
        errorText.className = "text-sm text-red-400";
        errorText.textContent = "用户信息加载失败";
        infoText.appendChild(errorText);
      }
      section.appendChild(infoText);
      return section;
    }
    /**
     * 创建同步按钮区域
     */
    createSyncSection() {
      const section = document.createElement("div");
      section.className = "flex flex-col items-center";
      const isUserInfoValid = this.userInfo && !("error" in this.userInfo);
      const disabledClass = isUserInfoValid ? "" : " opacity-50 cursor-not-allowed";
      const disabledBgClass = isUserInfoValid ? "bg-gray-700 hover:bg-gray-600" : "bg-gray-800";
      const mainSyncButton = document.createElement("button");
      mainSyncButton.className = `flex items-center justify-center px-6 py-2 ${disabledBgClass} text-white font-medium rounded-lg transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed mb-2${disabledClass}`;
      mainSyncButton.disabled = !isUserInfoValid;
      mainSyncButton.innerHTML = `
      <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
      </svg>
      <span class="sync-text">${isUserInfoValid ? "同步全部" : "请先登录"}</span>
    `;
      const expandButton = document.createElement("button");
      expandButton.className = `flex items-center justify-center px-4 py-1 ${isUserInfoValid ? "bg-gray-600 hover:bg-gray-500" : "bg-gray-700"} text-white text-sm rounded transition-all duration-200${disabledClass}`;
      expandButton.disabled = !isUserInfoValid;
      expandButton.innerHTML = `
      <span class="mr-1 text-xs">更多选项</span>
      <svg class="w-3 h-3 expand-icon transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
      </svg>
    `;
      if (isUserInfoValid) {
        mainSyncButton.addEventListener("click", () => this.handleSyncAll(mainSyncButton));
        expandButton.addEventListener("click", () => this.toggleExpanded(expandButton));
      }
      const detailsContainer = document.createElement("div");
      detailsContainer.className = "w-full mt-2 overflow-hidden transition-all duration-300";
      detailsContainer.style.maxHeight = "0";
      detailsContainer.style.opacity = "0";
      const detailsContent = this.createDetailedSyncOptions();
      detailsContainer.appendChild(detailsContent);
      section.appendChild(mainSyncButton);
      section.appendChild(expandButton);
      section.appendChild(detailsContainer);
      return section;
    }
    /**
     * 创建详细同步选项
     */
    createDetailedSyncOptions() {
      const container = document.createElement("div");
      container.className = "grid grid-cols-2 gap-2";
      const isUserInfoValid = this.userInfo && !("error" in this.userInfo);
      const syncOptions = [
        {
          text: "同步电量",
          icon: `<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
        </svg>`,
          handler: (event) => this.handleSyncResin(event)
        },
        {
          text: "同步角色",
          icon: `<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
        </svg>`,
          handler: (event) => this.handleSyncCharacters(event)
        },
        {
          text: "同步材料",
          icon: `<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path>
        </svg>`,
          handler: (event) => this.handleSyncItems(event)
        },
        {
          text: "重置设备",
          icon: `<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15M12 3v9m0 0l-3-3m3 3l3-3"></path>
        </svg>`,
          handler: (event) => this.handleResetDeviceInfo(event)
        }
      ];
      syncOptions.forEach((option) => {
        const button = document.createElement("button");
        const buttonClass = isUserInfoValid ? "bg-gray-600 hover:bg-gray-500" : "bg-gray-700 opacity-50 cursor-not-allowed";
        button.className = `flex items-center justify-center px-3 py-2 ${buttonClass} text-white text-sm font-medium rounded transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed`;
        button.disabled = !isUserInfoValid;
        button.innerHTML = `${option.icon}<span class="sync-text">${option.text}</span>`;
        if (isUserInfoValid) {
          button.addEventListener("click", option.handler);
        }
        container.appendChild(button);
      });
      return container;
    }
    /**
     * 切换展开状态
     */
    toggleExpanded(expandButton) {
      if (this.isLoading) return;
      this.isExpanded = !this.isExpanded;
      const detailsContainer = this.container?.querySelector(".overflow-hidden");
      const expandIcon = expandButton.querySelector(".expand-icon");
      if (this.isExpanded) {
        detailsContainer.style.maxHeight = "200px";
        detailsContainer.style.opacity = "1";
        expandIcon.style.transform = "rotate(180deg)";
      } else {
        detailsContainer.style.maxHeight = "0";
        detailsContainer.style.opacity = "0";
        expandIcon.style.transform = "rotate(0deg)";
      }
    }
    /**
     * 处理同步全部按钮点击
     */
    async handleSyncAll(button) {
      if (this.isLoading) return;
      if (!button) {
        button = this.container?.querySelector(".sync-text")?.closest("button");
        if (!button) return;
      }
      await this.performSyncOperation(button, "同步中...", async () => {
        logger.debug("开始同步全部数据...");
        await this.performSync();
        logger.debug("✅ 同步完成");
      });
    }
    /**
     * 处理同步电量
     */
    async handleSyncResin(event) {
      const button = event?.target?.closest("button");
      if (!button) return;
      await this.performSyncOperation(button, "同步中...", async () => {
        logger.debug("开始同步电量数据...");
        const success = await syncResinData();
        if (!success) {
          throw new Error("电量同步失败");
        }
        logger.debug("✅ 电量同步完成");
      });
    }
    /**
     * 处理同步角色
     */
    async handleSyncCharacters(event) {
      const button = event?.target?.closest("button");
      if (!button) return;
      await this.performSyncOperation(button, "同步中...", async () => {
        logger.debug("开始同步角色数据...");
        const result = await syncAllCharacters();
        if (result.success === 0) {
          throw new Error("角色同步失败");
        }
        logger.debug("✅ 角色同步完成");
      });
    }
    /**
     * 处理同步材料
     */
    async handleSyncItems(event) {
      const button = event?.target?.closest("button");
      if (!button) return;
      await this.performSyncOperation(button, "同步中...", async () => {
        logger.debug("开始同步材料数据...");
        const success = await syncItemsData();
        if (!success) {
          throw new Error("材料同步失败");
        }
        logger.debug("✅ 材料同步完成");
      });
    }
    /**
     * 处理重置设备信息
     */
    async handleResetDeviceInfo(event) {
      const button = event?.target?.closest("button");
      if (!button) return;
      await this.performSyncOperation(button, "重置中...", async () => {
        logger.debug("开始重置设备信息...");
        try {
          await refreshDeviceInfo();
          logger.debug("✅ 设备信息重置完成");
          setToast("设备信息已重置", "success");
        } catch (error) {
          logger.error("设备信息重置失败:", error);
          setToast("设备信息重置失败", "error");
        }
      });
    }
    /**
     * 通用同步操作处理器
     */
    async performSyncOperation(button, loadingText, syncOperation) {
      if (this.isLoading) return;
      this.isLoading = true;
      const syncText = button.querySelector(".sync-text");
      const originalText = syncText.textContent;
      try {
        this.setAllButtonsDisabled(true);
        syncText.textContent = loadingText;
        const icon = button.querySelector("svg");
        if (icon) {
          icon.classList.add("animate-spin");
        }
        await syncOperation();
        this.showSyncResult(button, syncText, originalText, icon, "success");
      } catch (error) {
        logger.error("同步失败:", error);
        const icon = button.querySelector("svg");
        this.showSyncResult(button, syncText, originalText, icon, "error");
      }
    }
    /**
     * 执行同步操作
     */
    async performSync() {
      try {
        logger.debug("开始执行完整同步...");
        const result = await syncAll();
        const { resinSync, characterSync, itemsSync } = result;
        const totalSuccess = resinSync && characterSync.success > 0 && itemsSync;
        if (!totalSuccess) {
          const errorMessages = [];
          if (!resinSync) errorMessages.push("电量同步失败");
          if (characterSync.success === 0) {
            const charErrors = characterSync.errors || ["角色同步失败"];
            errorMessages.push(...charErrors);
          }
          if (!itemsSync) errorMessages.push("养成材料同步失败");
          const errorMessage = errorMessages.length > 0 ? errorMessages.join(", ") : "同步过程中出现错误";
          throw new Error(errorMessage);
        }
        logger.info(`✅ 同步完成 - 电量: ${resinSync ? "成功" : "失败"}, 角色: ${characterSync.success}/${characterSync.total}, 养成材料: ${itemsSync ? "成功" : "失败"}`);
      } catch (error) {
        logger.error("同步操作失败:", error);
        throw error;
      }
    }
    /**
     * 设置所有按钮的禁用状态
     */
    setAllButtonsDisabled(disabled) {
      if (!this.container) return;
      const buttons = this.container.querySelectorAll("button");
      buttons.forEach((button) => {
        button.disabled = disabled;
      });
    }
    /**
     * 显示同步结果
     */
    showSyncResult(button, syncText, originalText, icon, type) {
      const isSuccess = type === "success";
      syncText.textContent = isSuccess ? "同步完成" : "同步失败";
      const originalBgClass = button.className.match(/bg-gray-\d+/)?.[0] || "bg-gray-700";
      const originalHoverClass = button.className.match(/hover:bg-gray-\d+/)?.[0] || "hover:bg-gray-600";
      const newColorClass = isSuccess ? "bg-green-600" : "bg-red-600";
      const newHoverClass = isSuccess ? "hover:bg-green-700" : "hover:bg-red-700";
      button.className = button.className.replace(originalBgClass, newColorClass).replace(originalHoverClass, newHoverClass);
      setTimeout(() => {
        syncText.textContent = originalText || "同步全部";
        button.className = button.className.replace(newColorClass, originalBgClass).replace(newHoverClass, originalHoverClass);
        if (icon) {
          icon.classList.remove("animate-spin");
        }
        this.setAllButtonsDisabled(false);
        this.isLoading = false;
      }, 2e3);
    }
    /**
     * 销毁面板
     */
    destroy() {
      if (this.container && this.container.parentNode) {
        this.container.parentNode.removeChild(this.container);
        this.container = null;
      }
      const allPanels = document.querySelectorAll(SeeliePanel.PANEL_SELECTOR);
      allPanels.forEach((panel) => {
        if (panel.parentNode) {
          panel.parentNode.removeChild(panel);
        }
      });
      logger.debug("Seelie 面板已销毁");
    }
    /**
     * 刷新组件(实现接口要求)
     */
    async refresh() {
      await this.refreshUserInfo();
    }
    /**
     * 刷新用户信息
     */
    async refreshUserInfo() {
      try {
        if (this.container) {
          const parent = this.container.parentNode;
          if (parent) {
            this.destroy();
            await this.createPanel();
          }
        }
      } catch (error) {
        logger.error("刷新用户信息失败:", error);
      }
    }
  }
  function registerSeeliePanel() {
    const config = {
      id: "seelie-panel",
      targetSelector: SeeliePanel.TARGET_SELECTOR,
      componentSelector: SeeliePanel.PANEL_SELECTOR,
      condition: () => {
        return true;
      }
    };
    domInjector.register(config, () => new SeeliePanel());
    logger.debug("📝 Seelie 面板组件注册完成");
  }
  const componentRegisters = {
    seeliePanel: registerSeeliePanel
  };
  function registerAllComponents() {
    logger.debug("🎯 开始注册所有组件");
    Object.values(componentRegisters).forEach((register) => register());
    logger.debug("✅ 所有组件注册完成");
  }
  function initApp() {
    logger.log("🎯 zzz-seelie-sync 脚本已加载");
    initDOMInjector();
  }
  function initDOMInjector() {
    try {
      if (domInjector.isInit()) {
        logger.debug("DOM 注入管理器已初始化,跳过");
        return;
      }
      registerAllComponents();
      domInjector.init();
      logger.debug("✅ DOM 注入管理器初始化完成");
    } catch (error) {
      logger.error("❌ 初始化 DOM 注入管理器失败:", error);
    }
  }
  initApp();

})(GM_fetch);