ZZZ Seelie 数据同步

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

// ==UserScript==
// @name         ZZZ Seelie 数据同步
// @namespace    github.com/owwkmidream
// @version      1.2.2
// @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://www.miyoushe.com/zzz/";
  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("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 {
        await this.loadUserInfo();
        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);