(function () {
  // 主预览卡片类
  class PreviewCard {
    constructor(container, options = {}) {
      this.container = container;
      this.options = {
        fps: 8,
        onFpsChange: null,
        ...options
      };
      
      this.previewImage = null;
      this.loadingOverlay = null;
      this.dropHint = null;
      this.imageError = null;
      this.fpsSlider = null;
      this.fpsValue = null;
      this.dropZone = null;
      
      this.currentFps = this.options.fps;
      this.frameList = [];
      this.currentFrameIndex = 0;
      this.animationTimer = null;
      this.frameSourceMode = "remote";
      this.localFrameResources = [];
      this.currentFolderName = '';
      
      // 当前登录用户名
      this.currentUsername = null;
      
      this.init();
      this.initUserListener();
    }
    
    // 获取当前登录用户名
    getCurrentUsername() {
      // 如果已经缓存了用户名，直接返回
      if (this.currentUsername) {
        return this.currentUsername;
      }
      
      // 从导航栏 iframe 中获取用户名
      try {
        let targetWindow = window.parent;
        while (targetWindow && targetWindow !== window) {
          try {
            const navigationFrame = targetWindow.document.getElementById('navigationFrame');
            if (navigationFrame && navigationFrame.contentWindow) {
              const navWindow = navigationFrame.contentWindow;
              const navDoc = navigationFrame.contentDocument || navWindow.document;
              
              // 检查用户是否已登录
              const userAvatarContainer = navDoc.getElementById('userAvatarContainer');
              if (userAvatarContainer) {
                const computedStyle = navDoc.defaultView.getComputedStyle(userAvatarContainer);
                if (computedStyle.display !== 'none') {
                  // 用户已登录，从 userAvatar 的 alt 属性获取用户名
                  const userAvatar = navDoc.getElementById('userAvatar');
                  if (userAvatar && userAvatar.alt && userAvatar.alt !== '用户头像') {
                    const username = userAvatar.alt;
                    this.currentUsername = username;
                    return username;
                  }
                }
              }
            }
          } catch (e) {
            // 跨域或访问限制，继续尝试上层窗口
          }
          
          if (targetWindow.parent && targetWindow.parent !== targetWindow) {
            targetWindow = targetWindow.parent;
          } else {
            break;
          }
        }
      } catch (error) {
        console.warn('[PreviewCard] 无法获取用户名:', error);
      }
      
      return this.currentUsername;
    }
    
    // 监听登录成功消息
    initUserListener() {
      window.addEventListener('message', (event) => {
        if (event.data && event.data.type === 'login-success' && event.data.user) {
          this.currentUsername = event.data.user.username;
        } else if (event.data && event.data.type === 'logout') {
          this.currentUsername = null;
        }
      });
    }
    
    async init() {
      await this.loadTemplate();
      this.bindElements();
      this.bindEvents();
      this.setStagePlaceholderVisible(true);
      
      // 从 localStorage 恢复登录状态
      this.restoreLoginFromStorage();
    }
    
    // 从 localStorage 恢复登录状态
    restoreLoginFromStorage() {
      try {
        const loginDataStr = localStorage.getItem('loginData');
        if (!loginDataStr) {
          return;
        }
        
        const loginData = JSON.parse(loginDataStr);
        const now = Date.now();
        
        // 检查是否过期
        if (now >= loginData.expireTime) {
          localStorage.removeItem('loginData');
          return;
        }
        
        // 未过期，恢复登录状态
        if (loginData.user && loginData.user.username) {
          this.currentUsername = loginData.user.username;
          console.log('[PreviewCard] 从 localStorage 恢复登录状态:', loginData.user.username);
        }
      } catch (error) {
        console.error('[PreviewCard] 恢复登录状态失败:', error);
      }
    }
    
    async loadTemplate() {
      const response = await fetch('./card.html');
      const html = await response.text();
      const wrapper = document.createElement('div');
      wrapper.innerHTML = html.trim();
      const template = wrapper.querySelector('#preview-card-template');
      if (!template) {
        throw new Error('Preview card template not found');
      }
      const content = template.content.cloneNode(true);
      this.container.appendChild(content);
    }
    
    bindElements() {
      this.previewImage = this.container.querySelector('.preview-image');
      this.loadingOverlay = this.container.querySelector('.loading-overlay');
      this.loadingText = this.container.querySelector('.loading-text');
      this.dropHint = this.container.querySelector('.drop-hint');
      this.imageError = this.container.querySelector('.image-error');
      this.fpsSlider = this.container.querySelector('.fps-slider');
      this.fpsValue = this.container.querySelector('.fps-value');
      this.dropZone = this.container.querySelector('.preview-card-stage');
      this.infoBar = this.container.querySelector('.preview-info-bar');
      this.folderNameElement = this.container.querySelector('.folder-name');
      this.btnExport = this.container.querySelector('.btn-export');
      this.btnDownload = this.container.querySelector('.btn-download');
      this.btnAI = this.container.querySelector('.btn-ai');
    }
    
    bindEvents() {
      // FPS控制
      if (this.fpsSlider) {
        this.fpsSlider.addEventListener('input', () => {
          const value = parseInt(this.fpsSlider.value, 10) || this.currentFps;
          this.setFps(value);
          if (this.fpsValue) {
            this.fpsValue.textContent = `${value} FPS`;
          }
          if (typeof this.options.onFpsChange === 'function') {
            this.options.onFpsChange(value);
          }
        });
      }
      
      // 拖放事件
      if (this.dropZone) {
        this.dropZone.addEventListener('dragenter', (e) => this.handleDragEnter(e));
        this.dropZone.addEventListener('dragover', (e) => this.handleDragOver(e));
        this.dropZone.addEventListener('dragleave', (e) => this.handleDragLeave(e));
        this.dropZone.addEventListener('drop', (e) => this.handleDrop(e));
      }
      
      // 导出按钮（旧版兼容）
      if (this.btnExport) {
        this.btnExport.addEventListener('click', () => this.handleExport());
      }
      
      // 下载按钮
      if (this.btnDownload) {
        this.btnDownload.addEventListener('click', () => this.handleExport());
      }
      
      // AI生图按钮
      if (this.btnAI) {
        this.btnAI.addEventListener('click', () => this.handleAIGenerate());
      }
    }
    
    handleDragEnter(event) {
      event.preventDefault();
      event.stopPropagation();
      this.dropZone.classList.add('is-dragging');
    }
    
    handleDragOver(event) {
      event.preventDefault();
      event.stopPropagation();
    }
    
    handleDragLeave(event) {
      event.preventDefault();
      if (!this.dropZone.contains(event.relatedTarget)) {
        this.dropZone.classList.remove('is-dragging');
      }
    }
    
    async handleDrop(event) {
      event.preventDefault();
      event.stopPropagation();
      this.dropZone.classList.remove('is-dragging');
      
      // 获取拖入的文件夹名称
      const transfer = event.dataTransfer;
      if (!transfer || !transfer.items || transfer.items.length === 0) {
        // console.warn('[PreviewCard] No data transfer items');
        return;
      }
      
      // 获取文本数据（可能是JSON对象或文件夹名称）
      const item = transfer.items[0];
      if (item.kind === 'string' && item.type === 'text/plain') {
        item.getAsString(async (dataString) => {
          // console.log('[PreviewCard] Dropped folder:', dataString);
          
          // 尝试解析为JSON对象
          let folderName = dataString;
          let fileType = 'directory'; // 默认假设是文件夹
          let pngCount = undefined; // PNG文件数量（如果有）
          
          try {
            const data = JSON.parse(dataString);
            // 如果是对象，提取路径、名称和类型
            if (data && typeof data === 'object') {
              folderName = data.path || data.name || dataString;
              fileType = data.type || 'directory';
              pngCount = data.pngCount; // 从拖拽数据中获取PNG数量
            }
          } catch (e) {
            // 如果不是JSON，直接使用原始字符串
            folderName = dataString;
          }
          
          // 验证：必须是文件夹
          if (fileType !== 'directory') {
            this.showError('❌ 请拖入文件夹，不支持单个文件');
            return;
          }
          
          // 验证：文件夹中是否包含PNG图片
          const isValid = await this.validateFolderHasPNG(folderName, pngCount);
          if (!isValid) {
            this.showError('❌ 该文件夹不包含PNG图片');
            return;
          }
          
          // console.log('[PreviewCard] Resolved folder name:', folderName);
          await this.loadAndCacheFolderAnimation(folderName);
        });
      }
    }
    
    async validateFolderHasPNG(folderName, pngCount) {
      try {
        // 1. 优先使用传递的pngCount（来自拖拽数据）
        if (pngCount !== undefined) {
          // console.log('[PreviewCard] 使用缓存的pngCount:', pngCount);
          return pngCount > 0;
        }
        
        // 2. 尝试从DiskManager的缓存中获取
        if (window.diskManager && window.diskManager.getFileFromCache) {
          const cachedFile = window.diskManager.getFileFromCache(folderName);
          if (cachedFile && cachedFile.pngCount !== undefined) {
            // console.log('[PreviewCard] 从DiskManager缓存获取pngCount:', cachedFile.pngCount);
            return cachedFile.pngCount > 0;
          }
        }
        
        // 3. 最后才请求服务器（使用新的disk API）
        // console.log('[PreviewCard] 请求服务器验证文件夹:', folderName);
        const username = this.getCurrentUsername();
        if (!username) {
          return false;
        }
        const response = await fetch(`/api/disk/list?username=${encodeURIComponent(username)}&path=${encodeURIComponent(folderName)}`);
        if (!response.ok) {
          return false;
        }
        
        const data = await response.json();
        
        // 检查是否是文件夹并且有PNG文件
        if (data.success && data.files) {
          // 检查当前路径对应的文件夹信息
          // 注意：list API返回的是文件夹内的文件列表，不是文件夹本身
          // 所以我们需要统计PNG文件数量
          const pngFiles = data.files.filter(f => 
            f.type === 'file' && f.name.toLowerCase().endsWith('.png')
          );
          return pngFiles.length > 0;
        }
        
        return false;
        } catch (error) {
          // console.error('[PreviewCard] 验证文件夹失败:', error);
          return false;
        }
    }
    
    async loadAndCacheFolderAnimation(folderName) {
      try {
        // 显示加载动画
        this.showLoading(true);
        this.hideError();
        this.setStagePlaceholderVisible(false);
        
        // console.log('[PreviewCard] 开始加载文件夹:', folderName);
        
        // 1. 从网盘系统获取该文件夹的文件列表
        const username = this.getCurrentUsername();
        if (!username) {
          throw new Error('请先登录');
        }
        const listResponse = await fetch(`/api/disk/list?username=${encodeURIComponent(username)}&path=${encodeURIComponent(folderName)}`);
        if (!listResponse.ok) {
          throw new Error('获取文件列表失败');
        }
        
        const listData = await listResponse.json();
        // console.log('[PreviewCard] 文件列表响应:', listData);
        
        if (!listData.success || !listData.files) {
          throw new Error('获取文件列表失败');
        }
        
        // 2. 筛选出PNG文件并按文件名排序
        const pngFiles = listData.files
          .filter(f => f.type === 'file' && f.name.toLowerCase().endsWith('.png'))
          .sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true }));
        
        // console.log('[PreviewCard] PNG文件列表:', pngFiles.map(f => f.name));
        
        if (!pngFiles.length) {
          throw new Error('文件夹中没有可用的PNG图片');
        }
        
        // console.log('[PreviewCard] 找到 PNG 文件数量:', pngFiles.length);
        
        // 3. 打开或创建缓存
        const cache = await caches.open('animation-frames-v1');
        
        // 4. 构造帧URL列表（使用文件的实际名称）
        const frameUrls = pngFiles.map(file => {
          // 使用文件的完整路径（file.path）来构造URL
          const username = this.getCurrentUsername();
          if (!username) {
            return null; // 未登录时返回 null
          }
          return `/api/disk/preview?username=${encodeURIComponent(username)}&path=${encodeURIComponent(file.path)}`;
        });
        
        // console.log('[PreviewCard] 开始下载和缓存图片...');
        
        // 5. 逐个下载并缓存
        const cachedFrames = [];
        for (let i = 0; i < frameUrls.length; i++) {
          const url = frameUrls[i];
          const fileName = pngFiles[i].name;
          
          // 更新进度
          this.showLoading(true, `正在缓存图片... (${i + 1}/${frameUrls.length})`);
          
          // 检查缓存中是否已存在
          const cachedResponse = await cache.match(url);
          if (cachedResponse) {
            // console.log(`[PreviewCard] [${i + 1}/${frameUrls.length}] 从缓存加载: ${fileName}`);
            cachedFrames.push({ url, index: i, name: fileName });
          } else {
            // 下载并缓存
            try {
              // console.log(`[PreviewCard] [${i + 1}/${frameUrls.length}] 下载: ${fileName}`);
              const response = await fetch(url);
              if (response.ok) {
                await cache.put(url, response.clone());
                // console.log(`[PreviewCard] ✓ 已缓存: ${fileName}`);
                cachedFrames.push({ url, index: i, name: fileName });
              } else {
                // console.warn(`[PreviewCard] ✗ 下载失败 (${response.status}): ${fileName}`);
              }
            } catch (error) {
              // console.error(`[PreviewCard] ✗ 下载错误: ${fileName}`, error);
            }
          }
        }
        
        if (cachedFrames.length === 0) {
          throw new Error('没有成功缓存任何图片');
        }
        
        // console.log('[PreviewCard] ✅ 缓存完成，共', cachedFrames.length, '帧');
        
        // 6. 设置文件夹名称
        this.setFolderName(folderName);
        
        // 7. 加载并播放动画
        this.loadFrames(cachedFrames, 'cached');
        this.showLoading(false);
        
        // 添加播放状态类
        if (this.dropZone) {
          this.dropZone.classList.add('is-playing');
        }
        
      } catch (error) {
        // console.error('[PreviewCard] 加载失败:', error);
        this.showLoading(false);
        this.showError(error.message || '加载失败');
        this.setStagePlaceholderVisible(true);
        this.setFolderName(''); // 清除文件夹名称
        // 移除播放状态
        if (this.dropZone) {
          this.dropZone.classList.remove('is-playing');
        }
      }
    }
    
    sanitizeFrameList(frameInfo) {
      if (frameInfo && Array.isArray(frameInfo.frames) && frameInfo.frames.length > 0) {
        return frameInfo.frames;
      }
      const maxFrame = frameInfo && frameInfo.maxFrame ? frameInfo.maxFrame : 0;
      if (!maxFrame) {
        return [];
      }
      return Array.from({ length: maxFrame }, (_, idx) => idx + 1);
    }
    
    showLoading(isLoading, text = '正在加载图片...') {
      if (!this.loadingOverlay) return;
      if (isLoading) {
        this.loadingOverlay.classList.add('is-visible');
        this.loadingOverlay.setAttribute('aria-hidden', 'false');
        if (this.loadingText) {
          this.loadingText.textContent = text;
        }
      } else {
        this.loadingOverlay.classList.remove('is-visible');
        this.loadingOverlay.setAttribute('aria-hidden', 'true');
      }
    }
    
    showError(message) {
      // 使用全局alert显示错误
      this.showGlobalAlert(message);
    }
    
    hideError() {
      if (!this.imageError) return;
      this.imageError.hidden = true;
    }
    
    showGlobalAlert(text, duration = 1500) {
      // 直接调用父窗口的 GlobalAlert（不通过 postMessage）
      try {
        // 向上查找有 GlobalAlert 的窗口
        let targetWindow = window.parent;
        while (targetWindow && targetWindow !== window) {
          if (targetWindow.GlobalAlert) {
            targetWindow.GlobalAlert.show(text, duration);
            return;
          }
          if (targetWindow.parent && targetWindow.parent !== targetWindow) {
            targetWindow = targetWindow.parent;
          } else {
            break;
          }
        }
        
        // 降级处理
        console.log('[Alert]', text);
      } catch (error) {
        console.error('[Card] 显示 alert 失败:', error);
      }
    }
    
    setStagePlaceholderVisible(isVisible) {
      if (this.dropHint) {
        this.dropHint.hidden = !isVisible;
      }
      if (this.previewImage) {
        this.previewImage.classList.toggle('is-hidden', isVisible);
        if (isVisible) {
          this.previewImage.removeAttribute('src');
        }
      }
    }
    
    setFolderName(name) {
      this.currentFolderName = name;
      if (this.folderNameElement) {
        this.folderNameElement.textContent = name || '--';
      }
      if (this.infoBar) {
        this.infoBar.hidden = !name;
      }
    }
    
    async handleExport() {
      if (!this.currentFolderName || !this.frameList.length) {
        this.showGlobalAlert('没有可导出的动画');
        return;
      }
      
      // 直接打开导出弹出框，不先生成预览图
      // 预览图将在弹出框中生成
      this.openExportView();
    }
    
    /**
     * 处理AI生图按钮点击
     */
    async handleAIGenerate() {
      if (!this.currentFolderName || !this.frameList.length) {
        this.showGlobalAlert('没有可用于AI生图的动画');
        return;
      }
      
      // 打开AI生图界面
      this.openAIGenerateView();
    }
    
    /**
     * 打开AI生图界面
     */
    openAIGenerateView() {
      // 先生成预览图数据，然后打开AI生图界面
      this.generatePreviewImage().then(result => {
        // 向所有父级窗口发送消息（处理多层iframe情况）
        let targetWindow = window.parent;
        while (targetWindow && targetWindow !== window) {
          targetWindow.postMessage({
            type: 'open-ai-generate-view',
            folderName: this.currentFolderName,
            spritesheetData: result.imageUrl,
            spritesheetLayout: result.layout
          }, '*');
          
          // 尝试向更上层发送
          if (targetWindow.parent && targetWindow.parent !== targetWindow) {
            targetWindow = targetWindow.parent;
          } else {
            break;
          }
        }
      }).catch(error => {
        console.error('[PreviewCard] 生成预览图失败:', error);
        this.showGlobalAlert('生成预览图失败：' + error.message);
      });
    }
    
    /**
     * 生成预览图
     * @returns {Promise<string>} 预览图的 base64 URL
     */
    async generatePreviewImage() {
      const folderName = this.currentFolderName;
      
      // 获取用户名
      const username = this.getCurrentUsername();
      if (!username) {
        throw new Error('请先登录');
      }
      
      // 获取帧列表（从服务端获取，服务端会判断是否有图片）
      const encodedFolderName = encodeURIComponent(folderName);
      let apiUrl = `http://localhost:3000/api/frames/${encodedFolderName}`;
      if (username) {
        apiUrl += `?username=${encodeURIComponent(username)}`;
      }
      const response = await fetch(apiUrl);
      
      if (!response.ok) {
        // 服务端返回错误，解析错误信息
        const errorData = await response.json().catch(() => ({}));
        throw new Error(errorData.error || '无法获取帧列表');
      }
      
      const data = await response.json();
      const frameNumbers = data.frames || [];
      
      // 服务端已经判断过是否有图片，如果返回200但frames为空，说明有问题
      if (frameNumbers.length === 0) {
        throw new Error('该文件夹中没有图片');
      }
      
      // 加载所有图片（使用正确的API路径）
      const images = [];
      for (let i = 0; i < frameNumbers.length; i++) {
        const frameNum = frameNumbers[i];
        const frameName = frameNum.toString().padStart(2, '0');
        // 使用API路径，从用户目录加载
        const imagePath = `${folderName}/${frameName}.png`;
        const imgSrc = `/api/disk/preview?username=${encodeURIComponent(username)}&path=${encodeURIComponent(imagePath)}`;
        
        const img = await new Promise((resolve, reject) => {
          const image = new Image();
          image.crossOrigin = 'anonymous';
          image.onload = () => resolve(image);
          image.onerror = () => reject(new Error(`Failed to load image: ${imgSrc}`));
          image.src = imgSrc;
        });
        
        images.push({
          img: img,
          width: img.width,
          height: img.height,
          frameNum: frameNum
        });
      }
      
      // 计算布局（简化版，使用简单的网格布局）
      const frameWidth = images[0].width;
      const frameHeight = images[0].height;
      const cols = Math.ceil(Math.sqrt(images.length));
      const rows = Math.ceil(images.length / cols);
      
      // 创建 Canvas 并绘制
      const canvas = document.createElement('canvas');
      canvas.width = frameWidth * cols;
      canvas.height = frameHeight * rows;
      const ctx = canvas.getContext('2d');
      
      // 填充透明背景
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      // 保存布局信息
      const layout = [];
      
      // 绘制所有图片
      images.forEach((item, index) => {
        const col = index % cols;
        const row = Math.floor(index / cols);
        const x = col * frameWidth;
        const y = row * frameHeight;
        ctx.drawImage(item.img, x, y);
        
        // 保存布局信息
        layout.push({
          x: x,
          y: y,
          width: item.width,
          height: item.height,
          frameNum: item.frameNum
        });
      });
      
      // 转换为 base64
      return new Promise((resolve) => {
        canvas.toBlob((blob) => {
          const reader = new FileReader();
          reader.onload = () => {
            resolve({
              imageUrl: reader.result,
              layout: {
                layout: layout,
                sheetWidth: canvas.width,
                sheetHeight: canvas.height
              }
            });
          };
          reader.readAsDataURL(blob);
        }, 'image/png');
      });
    }
    
    /**
     * 打开导出弹出框
     */
    openExportView() {
      // 通过postMessage通知父页面打开导出弹出框
      // 传递文件夹名称，让弹出框自己生成预览图
      let targetWindow = window.parent;
      while (targetWindow && targetWindow !== window) {
        targetWindow.postMessage({
          type: 'open-export-view',
          folderName: this.currentFolderName
        }, '*');
        
        // 尝试向更上层发送
        if (targetWindow.parent && targetWindow.parent !== targetWindow) {
          targetWindow = targetWindow.parent;
        } else {
          break;
        }
      }
    }
    
    setFps(fps) {
      this.currentFps = fps;
      if (this.frameList.length > 0) {
        this.startAnimation();
      }
    }
    
    startAnimation() {
      this.stopAnimation();
      if (!this.frameList.length) return;
      
      const interval = 1000 / this.currentFps;
      this.animationTimer = setInterval(() => {
        if (!this.frameList.length) {
          this.stopAnimation();
          return;
        }
        this.currentFrameIndex = (this.currentFrameIndex + 1) % this.frameList.length;
        this.updateFrame(this.frameList[this.currentFrameIndex]);
      }, interval);
    }
    
    stopAnimation() {
      if (this.animationTimer) {
        clearInterval(this.animationTimer);
        this.animationTimer = null;
      }
    }
    
    updateFrame(frameData) {
      if (!this.previewImage) return;
      
      if ((this.frameSourceMode === 'local' || this.frameSourceMode === 'cached') && frameData && frameData.url) {
        this.setStagePlaceholderVisible(false);
        if (this.previewImage.src !== frameData.url) {
          this.previewImage.src = frameData.url;
        }
      }
    }
    
    loadFrames(frames, mode = 'local') {
      this.frameSourceMode = mode;
      this.frameList = frames;
      this.currentFrameIndex = 0;
      
      // console.log('[PreviewCard] 加载帧列表, 模式:', mode, '数量:', frames.length);
      
      if (frames.length > 0) {
        this.updateFrame(frames[0]);
        this.startAnimation();
      }
    }
    
    destroy() {
      this.stopAnimation();
      if (this.container) {
        this.container.innerHTML = '';
      }
    }
  }
  
  // 小卡片类
  class SequenceCard {
    constructor(cardElement, folderName, index, buildFrameSrc, onSelect) {
      this.cardElement = cardElement;
      this.folderName = folderName;
      this.index = index;
      this.buildFrameSrc = buildFrameSrc;
      this.onSelect = onSelect;

      this.imageElement = cardElement.querySelector(".card-image");
      this.spinnerElement = cardElement.querySelector(".loading-spinner");
      this.errorElement = cardElement.querySelector(".image-error");
      this.labelElement = cardElement.querySelector(".card-label");
      this.downloadButton = cardElement.querySelector(".card-download-btn");

      this.handleCardClick = this.handleCardClick.bind(this);
      this.handleDownloadClick = this.handleDownloadClick.bind(this);

      this.init();
    }

    init() {
      this.cardElement.dataset.folder = this.folderName || "";
      this.cardElement.dataset.index = this.index;
      this.cardElement.dataset.valid = "true";

      if (this.labelElement) {
        this.labelElement.textContent = this.formatLabel(this.folderName);
      }

      this.cardElement.addEventListener("click", this.handleCardClick);

      if (this.downloadButton) {
        this.boundDownloadHandler = (event) => {
          event.stopPropagation();
          event.preventDefault();
          this.handleDownloadClick();
        };
        this.downloadButton.addEventListener("click", this.boundDownloadHandler);
      }

      this.bindImageEvents();
    }

    bindImageEvents() {
      if (!this.imageElement) {
        return;
      }

      this.imageElement.addEventListener("load", () => {
        this.toggleSpinner(false);
        this.hideError();
      });

      this.imageElement.addEventListener("error", () => {
        this.toggleSpinner(false);
        this.showError("图片加载失败");
      });
    }

    formatLabel(name) {
      if (!name) {
        return "--";
      }
      return name.replace(/_/g, " ").toUpperCase();
    }

    loadPreview() {
      if (!this.imageElement || !this.buildFrameSrc || !this.folderName) {
        return;
      }
      this.toggleSpinner(true);
      const previewSrc = this.buildFrameSrc(this.folderName, 1);
      if (this.imageElement.src !== previewSrc) {
        this.imageElement.src = previewSrc;
      }
    }

    setActive(isActive) {
      if (isActive) {
        this.cardElement.classList.add("is-active");
      } else {
        this.cardElement.classList.remove("is-active");
      }
    }

    handleCardClick() {
      if (typeof this.onSelect === "function") {
        this.onSelect(this.folderName, this.index);
      }
    }

    handleDownloadClick() {
      if (!this.folderName) {
        return;
      }
      if (window.SpriteSheetMaker && typeof window.SpriteSheetMaker.handleDownloadClick === "function") {
        window.SpriteSheetMaker.handleDownloadClick(this.folderName, this.index);
      }
    }

    toggleSpinner(visible) {
      if (!this.spinnerElement) {
        return;
      }
      this.spinnerElement.style.display = visible ? "block" : "none";
    }

    showError(message) {
      if (!this.errorElement) {
        return;
      }
      this.errorElement.textContent = message;
      this.errorElement.hidden = false;
    }

    hideError() {
      if (!this.errorElement) {
        return;
      }
      this.errorElement.hidden = true;
    }

    destroy() {
      this.cardElement.removeEventListener("click", this.handleCardClick);
      if (this.downloadButton && this.boundDownloadHandler) {
        this.downloadButton.removeEventListener("click", this.boundDownloadHandler);
      }
    }
  }

  window.PreviewCard = PreviewCard;
  window.SequenceCard = SequenceCard;
})();


