/**
 * 充电桩大盘 - 渲染模块
 */

import { state } from './state.js';
import { getIdleTime, getChargingTime, getOccupiedTime, formatRemainingTime } from './time.js';
import { renderDCChargingAnim } from './dc-anim.js';
import { getRandomQuote } from './quotes.js';
import { refreshCommentCounts } from './comment.js';
import { escapeHtml, refreshIcons } from './utils.js';
import { cleanupElectricBorders, initElectricBorders } from './electric-border.js';

/**
 * 功率别名配置
 * 数据库保存 7kW，前端显示 5kW
 * key: connector_name, value: 显示功率
 */
const POWER_ALIAS = {
  '1号枪': '5',
  '3号桩': '5',
  '4号桩': '5',
  '7号桩': '5',
  '11号桩': '5',
  '14号枪': '5'
};

/**
 * 获取显示功率（应用别名）
 */
function getDisplayPower(connectorName, originalPower) {
  return POWER_ALIAS[connectorName] || String(originalPower);
}

/**
 * 简化充电桩名称
 * - 公牛桩: "Giant内部充电桩（SSL-18）01" → "18号桩(公牛)"
 * - 公牛桩: "Giant内部充电桩（JSF-01）01" → "J01号桩(公牛)"
 * - NIO桩: 保持原名 "16号枪"、"17号枪"
 */
function simplifyConnectorName(name) {
  // 公牛桩名称匹配: Giant内部充电桩（SSL-18）01 或 JSF-01
  const sslMatch = name.match(/SSL-(\d+)/);
  if (sslMatch) {
    return `${sslMatch[1]}号桩(公牛)`;
  }
  const jsfMatch = name.match(/JSF-(\d+)/);
  if (jsfMatch) {
    return `J${jsfMatch[1]}号桩(公牛)`;
  }
  // NIO 桩保持原名
  return name;
}

/**
 * 提取充电桩编号用于排序
 * 支持格式: "16号枪", "17号枪", "18号桩(公牛)", "J01号桩(公牛)"
 */
function extractConnectorNumber(name) {
  const match = name.match(/(\d+)/);
  return match ? parseInt(match[1], 10) : 0;
}

/**
 * 判断是否为公牛桩（支持原始名称和简化名称）
 */
function isGongniuConnector(name) {
  // 支持简化后的名称
  if (name.includes('(公牛)')) return true;
  // 支持原始名称格式
  if (name.includes('Giant内部充电桩')) return true;
  if (name.match(/SSL-\d+/) || name.match(/JSF-\d+/)) return true;
  return false;
}

/**
 * 充电桩排序：NIO 桩在前，公牛桩在后；同类型按编号倒序
 */
function sortConnectors(connectors) {
  return connectors.sort((a, b) => {
    const aIsGongniu = isGongniuConnector(a.connector_name);
    const bIsGongniu = isGongniuConnector(b.connector_name);

    // 公牛桩排在后面
    if (aIsGongniu && !bIsGongniu) return 1;
    if (!aIsGongniu && bIsGongniu) return -1;

    // 同类型按编号倒序
    return extractConnectorNumber(b.connector_name) - extractConnectorNumber(a.connector_name);
  });
}

function renderElectricBorderLayers() {
  return `
    <div class="eb-canvas-container" aria-hidden="true">
      <canvas class="eb-canvas"></canvas>
    </div>
    <div class="eb-layers" aria-hidden="true">
      <div class="eb-glow-1"></div>
      <div class="eb-glow-2"></div>
      <div class="eb-background-glow"></div>
    </div>
  `;
}

/**
 * 渲染留言/调侃公共区块（消除 6 处重复）
 */
function renderJokeAndComment(connectorId, displayName, joke, borderClass) {
  const safeId = escapeHtml(connectorId);
  const safeName = escapeHtml(displayName);
  const safeJoke = escapeHtml(joke);
  const border = borderClass || '';
  return `
    <div id="joke-${safeId}" class="mt-auto pt-2 border-t ${border} text-[11px] text-slate-500 italic leading-relaxed relative z-10 whitespace-nowrap overflow-hidden text-ellipsis">
      "${safeJoke}"
    </div>
    <div class="pt-1.5 relative z-10">
      <div class="flex items-center justify-between">
        <span id="comment-count-${safeId}" data-comment-trigger data-connector-id="${safeId}" data-connector-name="${safeName}" class="text-[11px] text-slate-500 hidden cursor-pointer hover:text-cyan-400 transition-colors">
          <i data-lucide="message-circle" class="w-3 h-3 inline-block"></i> <span class="comment-count-text"></span>
        </span>
        <button data-comment-trigger data-connector-id="${safeId}" data-connector-name="${safeName}" class="text-[11px] text-slate-500 hover:text-cyan-400 transition-colors flex items-center gap-1 ml-auto">
          <i data-lucide="message-circle" class="w-3.5 h-3.5"></i> 留言
        </button>
      </div>
    </div>
  `;
}

/**
 * 隐藏骨架屏（首次数据加载后调用，只执行一次）
 */
let _skeletonHidden = false;
function hideSkeleton() {
  if (_skeletonHidden) return;
  _skeletonHidden = true;
  const el = document.getElementById('skeleton-screen');
  if (el) el.remove();
}

/**
 * 更新空状态显示
 */
function updateEmptyStates(dcCount, acCount) {
  const dcEmpty = document.getElementById('dc-empty');
  const acEmpty = document.getElementById('ac-empty');
  if (dcEmpty) dcEmpty.classList.toggle('hidden', dcCount > 0);
  if (acEmpty) acEmpty.classList.toggle('hidden', acCount > 0);
}

// 渲染状态缓存（用于差量更新）
let _lastRenderSignature = '';

/**
 * 生成单个充电桩的轻量签名
 */
function connectorSignature(c) {
  return `${c.connector_id}|${c.connector_name}|${c.type}|${c.power}|${c.vendor || ''}|${c.state.type}|${Math.round(c.charging_progress || 0)}|${c.idle_seconds || 0}|${c.charging_seconds || 0}|${c.occupied_seconds || 0}|${c.estimated_charging_ready_time ?? ''}`;
}

/**
 * 生成整站数据签名
 */
function buildRenderSignature(connectors, filter) {
  return filter + '::' + connectors.map(connectorSignature).sort().join(';');
}

/**
 * 差量更新网格中的卡片
 * - 未变化的卡片保留原 DOM（避免动画重启和 electric-border 重建）
 * - 变化/新增的卡片只替换对应节点
 * - 移除不再存在的卡片
 */
function diffUpdateGrid(grid, connectors) {
  const existingCards = grid.querySelectorAll(':scope > [data-connector-id]');
  const existingMap = new Map();
  existingCards.forEach(el => existingMap.set(el.dataset.connectorId, el));

  const currentOrder = Array.from(existingCards).map(el => el.dataset.connectorId).join(',');
  const newOrder = connectors.map(c => c.connector_id).join(',');
  const hasDataChange = connectors.some(c => {
    const existing = existingMap.get(c.connector_id);
    return !existing || existing.dataset.renderSig !== connectorSignature(c);
  });
  const hasChange = currentOrder !== newOrder || existingCards.length !== connectors.length || hasDataChange;
  if (!hasChange) return;

  // 使用 DocumentFragment 减少重排
  const fragment = document.createDocumentFragment();

  // 按顺序构建新的卡片列表
  connectors.forEach(c => {
    const existing = existingMap.get(c.connector_id);
    const currentSig = connectorSignature(c);

    if (existing && existing.dataset.renderSig === currentSig) {
      // 数据未变化，保留原 DOM
      fragment.appendChild(existing);
    } else {
      // 数据变化或新增，创建新卡片
      const wrapper = document.createElement('div');
      wrapper.innerHTML = renderCard(c);
      const newCard = wrapper.firstElementChild;
      if (newCard) {
        newCard.dataset.renderSig = currentSig;
        fragment.appendChild(newCard);
      }
    }
  });

  cleanupElectricBorders(grid);
  grid.querySelectorAll(':scope > [data-connector-id]').forEach(el => el.remove());
  grid.appendChild(fragment);
  initElectricBorders(grid);
}

/**
 * 渲染充电站数据（带差量更新）
 */
export function renderStation(station) {
  // 更新统计数字
  const stats = { all: 0, free: 0, charging: 0, occupied: 0, offline: 0 };
  station.connectors.forEach(c => {
    stats.all++;
    stats[c.state.type] = (stats[c.state.type] || 0) + 1;
  });

  document.getElementById('count-all').textContent = stats.all;
  document.getElementById('count-free').textContent = stats.free;
  document.getElementById('count-charging').textContent = stats.charging;
  document.getElementById('count-occupied').textContent = stats.occupied;

  // 生成当前数据签名，与上次比较
  const signature = buildRenderSignature(station.connectors, state.currentFilter);
  if (signature === _lastRenderSignature) {
    refreshCommentCounts(station.connectors.map(c => c.connector_id));
    return;
  }
  _lastRenderSignature = signature;

  // 根据筛选器渲染
  const filteredConnectors = state.currentFilter === 'all'
    ? station.connectors
    : station.connectors.filter(c => c.state.type === state.currentFilter);

  const dc = filteredConnectors.filter(c => c.type === 'DC');
  const ac = filteredConnectors.filter(c => c.type === 'AC');

  // 排序：NIO 桩在前，公牛桩在后
  sortConnectors(dc);
  sortConnectors(ac);

  const dcGrid = document.getElementById('dc-grid');
  const acGrid = document.getElementById('ac-grid');

  // 隐藏骨架屏（首次加载后）
  hideSkeleton();

  // 差量更新：只更新变化的卡片
  diffUpdateGrid(dcGrid, dc);
  diffUpdateGrid(acGrid, ac);

  // 更新空状态
  updateEmptyStates(dc.length, ac.length);

  refreshIcons();

  // 留言按钮事件委托（XSS 安全：使用 data 属性代替 inline onclick）
  if (!renderStation._delegationSetup) {
    renderStation._delegationSetup = true;
    const handleCommentClick = (e) => {
      const el = e.target.closest('[data-comment-trigger]');
      if (!el) return;
      const connectorId = el.getAttribute('data-connector-id');
      const connectorName = el.getAttribute('data-connector-name');
      if (!connectorId || !connectorName) return;
      window.showCommentModal(connectorId, connectorName);
    };
    document.getElementById('dc-grid').addEventListener('click', handleCommentClick);
    document.getElementById('ac-grid').addEventListener('click', handleCommentClick);
  }

  // 刷新留言数量
  const allConnectorIds = station.connectors.map(c => c.connector_id);
  refreshCommentCounts(allConnectorIds);
}

/**
 * 渲染单个卡片
 */
function renderCard(c) {
  const type = c.state.type;
  const idle = getIdleTime(c);
  const chargingTime = getChargingTime(c);
  const progress = c.charging_progress || 0;
  const remainingMins = c.estimated_charging_ready_time;
  const remainingText = formatRemainingTime(remainingMins);

  // 简化充电桩名称
  const displayName = simplifyConnectorName(c.connector_name);

  // 功率别名处理
  const displayPower = getDisplayPower(c.connector_name, c.power);
  const is5kw = displayPower === '5' && c.type === 'AC';

  // 充电中的副文本
  let chargingSubText = '';
  if (c.type === 'DC') {
    // DC 桩：显示已充时长 + 进度 + 剩余时长
    const parts = [];
    if (chargingTime.seconds > 0) {
      parts.push(`<i data-lucide="clock" class="w-3.5 h-3.5 opacity-80"></i> ${chargingTime.text}`);
    }
    if (progress) {
      parts.push(`<i data-lucide="zap" class="w-3.5 h-3.5 animate-pulse"></i> ${Math.round(progress)}%`);
    }
    if (remainingText) {
      parts.push(remainingText);
    }
    chargingSubText = parts.length > 0
      ? parts.join(' <span class="opacity-50 px-1">|</span> ')
      : '<i data-lucide="battery-charging" class="w-3.5 h-3.5 animate-pulse"></i> 充电中...';
  } else {
    // AC 桩：显示已充电时长
    chargingSubText = `<i data-lucide="clock" class="w-3.5 h-3.5 opacity-80"></i> ${chargingTime.text}`;
  }

  // UI 配置
  const occupiedTime = getOccupiedTime(c);
  const uiConfig = {
    free: {
      cardClass: 'card-free',
      color: 'text-emerald-400',
      icon: '<i data-lucide="car" class="w-8 h-8 text-emerald-400"></i>',
      title: '空闲可用',
      subText: idle.text,
      joke: getRandomQuote()
    },
    charging: {
      cardClass: 'card-charging',
      color: 'text-cyan-400',
      icon: '<i data-lucide="battery-charging" class="w-7 h-7 text-cyan-400 animate-pulse"></i>',
      title: '充电中',
      subText: chargingSubText,
      joke: c.type === 'DC' ? '卷王正在极速回血' : getRandomQuote()
    },
    occupied: {
      cardClass: 'card-occupied',
      color: 'text-orange-400',
      icon: '<i data-lucide="alert-triangle" class="w-8 h-8 text-orange-400"></i>',
      title: '占位中',
      subText: occupiedTime.text,
      joke: getRandomQuote()
    },
    offline: {
      cardClass: 'card-offline',
      color: 'text-slate-400',
      icon: '<i data-lucide="wifi-off" class="w-8 h-8 text-slate-400"></i>',
      title: '离线',
      subText: '设备异常',
      joke: '充电桩正在摸鱼，请稍后再来'
    }
  };

  const ui = uiConfig[type] || uiConfig.free;
  const isDCCharging = type === 'charging' && c.type === 'DC';
  const isDC = c.type === 'DC';
  const electricBorderAttrs = 'data-electric-color="#7df9ff" data-electric-speed="1.05" data-electric-chaos="0.14" data-electric-thickness="3" data-electric-radius="16"';

  // DC 充电动效层 (全息汽车透视)
  let dcAnimLayer = '';
  if (isDCCharging && progress) {
    dcAnimLayer = renderDCChargingAnim(progress, remainingMins, c.connector_name, chargingTime.seconds);
  }

  // 进度条层 (DC 充电时的背景填充)
  let progressLayer = '';
  let bottomProgress = '';

  if (isDCCharging && progress) {
    progressLayer = `
      <div class="progress-bar" style="height: ${progress}%;"></div>
    `;
    bottomProgress = `
      <div class="bottom-progress" style="width: ${progress}%;"></div>
    `;
  }

  // DC 卡片专属类
  const dcCardClass = isDC ? 'card-dc' : '';

  // DC 卡片使用更紧凑的布局
  if (isDC) {
    // 充电中时动画已包含状态文本，简化卡片状态区
    const dcStatusSection = isDCCharging && progress ? '' : `
      <div class="relative z-10 mt-1">
        <div class="text-sm font-semibold ${ui.color}">
          ${ui.title}
        </div>
        <div class="text-xs text-slate-400 mt-0.5 font-mono flex items-center gap-1">
          ${ui.subText}
        </div>
      </div>
    `;

    // DC 空闲、占位和离线状态使用更简洁的设计
    if (type === 'free' || type === 'occupied' || type === 'offline') {
      const bgClass = type === 'free' ? 'bg-emerald-400/10' : type === 'offline' ? 'bg-slate-400/10' : 'bg-orange-400/10';
      const cardBgClass = type === 'free' ? 'bg-emerald-500/10 border border-emerald-500/20' : type === 'offline' ? 'bg-slate-500/10 border border-slate-500/20' : 'bg-orange-500/10 border border-orange-500/20';
      const textClass = type === 'free' ? 'text-emerald-400' : type === 'offline' ? 'text-slate-400' : 'text-orange-400';
      const borderClass = type === 'free' ? 'border-emerald-500/10' : type === 'offline' ? 'border-slate-500/10' : 'border-orange-500/10';
      const icon = type === 'free' ? 'car' : type === 'offline' ? 'wifi-off' : 'alert-triangle';

      return `
        <div data-connector-id="${escapeHtml(c.connector_id)}" class="animate-card relative flex flex-col p-4 rounded-2xl border backdrop-blur-sm transition-all duration-300 hover:-translate-y-1 overflow-hidden ${ui.cardClass} ${dcCardClass}">
          <!-- 顶部标识 -->
          <div class="flex justify-between items-center mb-2 relative z-10">
            <div class="flex items-center gap-2">
              <div class="text-base font-bold text-slate-100">${escapeHtml(displayName)}</div>
              <div class="px-1.5 py-0.5 rounded bg-slate-800/90 border border-slate-700/60 text-[10px] font-semibold text-slate-400">
                ${c.power}kW
              </div>
            </div>
            <div class="p-1.5 rounded-lg bg-slate-900/60 ${ui.color}">
              ${ui.icon}
            </div>
          </div>

          <!-- 状态展示 -->
          <div class="flex-1 flex flex-col items-center justify-center py-4 relative z-10">
            <div class="relative mb-3">
              <div class="absolute inset-0 rounded-full ${bgClass} blur-xl scale-150"></div>
              <div class="relative p-4 rounded-2xl ${cardBgClass}">
                <i data-lucide="${icon}" class="w-10 h-10 ${textClass}"></i>
              </div>
            </div>
            <div class="${textClass} font-bold text-base tracking-wide">${ui.title}</div>
            <div class="text-slate-500 text-xs mt-1.5 font-mono flex items-center gap-1.5">
              <i data-lucide="${type === 'offline' ? 'alert-circle' : 'clock'}" class="w-3 h-3"></i> ${ui.subText}
            </div>
          </div>

          ${renderJokeAndComment(c.connector_id, displayName, ui.joke, borderClass)}
        </div>
      `;
    }

    return `
      <div data-connector-id="${escapeHtml(c.connector_id)}" class="animate-card electric-border relative flex flex-col p-4 rounded-2xl border backdrop-blur-sm transition-all duration-300 hover:-translate-y-1 overflow-hidden ${ui.cardClass} ${dcCardClass}" ${electricBorderAttrs}>
        ${renderElectricBorderLayers()}
        ${progressLayer}

        <!-- 顶部标识 -->
        <div class="flex justify-between items-center mb-2 relative z-10">
          <div class="flex items-center gap-2">
            <div class="text-base font-bold text-slate-100">${escapeHtml(displayName)}</div>
            <div class="px-1.5 py-0.5 rounded bg-slate-800/90 border border-slate-700/60 text-[10px] font-semibold text-slate-400">
              ${c.power}kW
            </div>
          </div>
          <div class="p-1.5 rounded-lg bg-slate-900/60 ${ui.color}">
            ${ui.icon}
          </div>
        </div>

        <!-- DC 充电动效 (全息汽车透视) -->
        ${dcAnimLayer}

        ${dcStatusSection}

        ${renderJokeAndComment(c.connector_id, displayName, ui.joke)}
      </div>
    `;
  }

  // 空闲卡片
  if (type === 'free') {
    // 5kW 特殊样式类
    const powerClass = is5kw ? 'power-5kw' : '';
    return `
      <div data-connector-id="${escapeHtml(c.connector_id)}" class="animate-card relative flex flex-col p-4 rounded-2xl border-2 transition-all duration-300 hover:-translate-y-1 overflow-hidden card-free ${powerClass}">
        <!-- 顶部标识 -->
        <div class="flex justify-between items-start mb-2 relative z-10">
          <div class="flex items-center gap-2">
            <div class="text-base font-bold text-slate-100">${escapeHtml(displayName)}</div>
            <div class="px-1.5 py-0.5 rounded-md ${is5kw ? 'bg-purple-900/40 border-purple-500/30 text-purple-400/70' : 'bg-emerald-900/40 border border-emerald-500/20 text-emerald-400/70'} text-[10px] font-semibold tracking-wide border">
              ${displayPower}kW
            </div>
          </div>
        </div>

        <!-- 空闲主视觉 -->
        <div class="flex-1 flex flex-col items-center justify-center py-3 relative z-10">
          <div class="relative mb-2">
            <div class="absolute inset-0 rounded-full ${is5kw ? 'bg-purple-400/10' : 'bg-emerald-400/10'} blur-xl scale-150"></div>
            <div class="relative p-3 rounded-2xl ${is5kw ? 'bg-purple-500/10 border border-purple-500/20' : 'bg-emerald-500/10 border border-emerald-500/20'}">
              <i data-lucide="car" class="w-8 h-8 ${is5kw ? 'text-purple-400' : 'text-emerald-400'}"></i>
            </div>
          </div>
          <div class="${is5kw ? 'text-purple-400' : 'text-emerald-400'} font-bold text-sm tracking-wide">空闲可用</div>
          <div class="text-slate-500 text-xs mt-1 font-mono flex items-center gap-1.5">
            <i data-lucide="clock" class="w-3 h-3"></i> ${ui.subText}
          </div>
        </div>

        ${renderJokeAndComment(c.connector_id, displayName, ui.joke, is5kw ? 'border-purple-500/10' : 'border-emerald-500/10')}
      </div>
    `;
  }

  // 占位卡片
  if (type === 'occupied') {
    // 5kW 特殊样式类
    const powerClass = is5kw ? 'power-5kw' : '';
    return `
      <div data-connector-id="${escapeHtml(c.connector_id)}" class="animate-card relative flex flex-col p-4 rounded-2xl border-2 transition-all duration-300 hover:-translate-y-1 overflow-hidden card-occupied ${powerClass}">
        <!-- 顶部标识 -->
        <div class="flex justify-between items-start mb-2 relative z-10">
          <div class="flex items-center gap-2">
            <div class="text-base font-bold text-slate-100">${escapeHtml(displayName)}</div>
            <div class="px-1.5 py-0.5 rounded-md ${is5kw ? 'bg-purple-900/40 border-purple-500/30 text-purple-400/70' : 'bg-orange-900/40 border border-orange-500/20 text-orange-400/70'} text-[10px] font-semibold tracking-wide border">
              ${displayPower}kW
            </div>
          </div>
        </div>

        <!-- 占位主视觉 -->
        <div class="flex-1 flex flex-col items-center justify-center py-3 relative z-10">
          <div class="relative mb-2">
            <div class="absolute inset-0 rounded-full bg-orange-400/10 blur-xl scale-150"></div>
            <div class="relative p-3 rounded-2xl bg-orange-500/10 border border-orange-500/20">
              <i data-lucide="alert-triangle" class="w-8 h-8 text-orange-400"></i>
            </div>
          </div>
          <div class="text-orange-400 font-bold text-sm tracking-wide">占位中</div>
          <div class="text-slate-500 text-xs mt-1 font-mono flex items-center gap-1.5">
            <i data-lucide="clock" class="w-3 h-3"></i> ${ui.subText}
          </div>
        </div>

        ${renderJokeAndComment(c.connector_id, displayName, ui.joke, 'border-orange-500/10')}
      </div>
    `;
  }

  // 离线卡片 (AC/DC 通用)
  if (type === 'offline') {
    return `
      <div data-connector-id="${escapeHtml(c.connector_id)}" class="animate-card relative flex flex-col p-4 rounded-2xl border-2 transition-all duration-300 hover:-translate-y-1 overflow-hidden card-offline">
        <!-- 顶部标识 -->
        <div class="flex justify-between items-start mb-2 relative z-10">
          <div class="flex items-center gap-2">
            <div class="text-base font-bold text-slate-100">${escapeHtml(displayName)}</div>
            <div class="px-1.5 py-0.5 rounded-md bg-slate-800/90 border border-slate-700/60 text-slate-500 text-[10px] font-semibold tracking-wide">
              ${displayPower}kW
            </div>
          </div>
        </div>

        <!-- 离线主视觉 -->
        <div class="flex-1 flex flex-col items-center justify-center py-3 relative z-10">
          <div class="relative mb-2">
            <div class="absolute inset-0 rounded-full bg-slate-400/10 blur-xl scale-150"></div>
            <div class="relative p-3 rounded-2xl bg-slate-500/10 border border-slate-500/20">
              <i data-lucide="wifi-off" class="w-8 h-8 text-slate-400"></i>
            </div>
          </div>
          <div class="text-slate-400 font-bold text-sm tracking-wide">离线</div>
          <div class="text-slate-500 text-xs mt-1 font-mono flex items-center gap-1.5">
            <i data-lucide="alert-circle" class="w-3 h-3"></i> 设备异常
          </div>
        </div>

        ${renderJokeAndComment(c.connector_id, displayName, ui.joke, 'border-slate-500/10')}
      </div>
    `;
  }

  // 充电中卡片 (AC)
  const powerClass = is5kw ? 'power-5kw' : '';
  return `
    <div data-connector-id="${escapeHtml(c.connector_id)}" class="animate-card electric-border relative flex flex-col p-4 rounded-2xl border-2 transition-all duration-300 hover:-translate-y-1 overflow-hidden card-charging ${powerClass}" ${electricBorderAttrs}>
      ${renderElectricBorderLayers()}
      ${progressLayer}

      <!-- 顶部标识 -->
      <div class="flex justify-between items-start mb-2 relative z-10">
        <div class="flex items-center gap-2">
          <div class="text-base font-bold text-slate-100">${escapeHtml(displayName)}</div>
          <div class="px-1.5 py-0.5 rounded-md ${is5kw ? 'bg-purple-900/40 border-purple-500/30 text-purple-400/70' : 'bg-slate-800/90 border border-slate-700/60 text-slate-400'} text-[10px] font-semibold tracking-wide border">
            ${displayPower}kW
          </div>
        </div>
      </div>

      <!-- 充电主视觉 -->
      <div class="flex-1 flex flex-col items-center justify-center py-3 relative z-10">
        <div class="relative mb-2">
          <div class="absolute inset-0 rounded-full bg-cyan-400/10 blur-xl scale-150"></div>
          <div class="relative p-3 rounded-2xl bg-cyan-500/10 border border-cyan-500/20">
            <i data-lucide="battery-charging" class="w-8 h-8 text-cyan-400 animate-pulse"></i>
          </div>
        </div>
        <div class="text-cyan-400 font-bold text-sm tracking-wide">${ui.title}</div>
        <div class="text-slate-500 text-xs mt-1 font-mono flex items-center gap-1.5">
          ${ui.subText}
        </div>
      </div>

      ${renderJokeAndComment(c.connector_id, displayName, ui.joke, 'border-cyan-500/10')}

      ${bottomProgress}
    </div>
  `;
}

/**
 * 设置筛选器
 */
export function setFilter(filter, station) {
  state.currentFilter = filter;
  _lastRenderSignature = ''; // 筛选器变化，强制重新渲染

  // 按钮基础类（包含响应式类，与 HTML 保持一致）
  const baseClasses = 'filter-btn flex items-center gap-1.5 md:gap-2 px-3 md:px-4 py-1.5 md:py-2 rounded-full text-xs md:text-sm font-medium transition-all duration-300 whitespace-nowrap';

  // 按钮状态样式配置
  const styles = {
    all: {
      active: 'bg-slate-800 text-white',
      inactive: 'text-slate-500 hover:text-slate-300 hover:bg-slate-800/50'
    },
    free: {
      active: 'bg-emerald-500/15 text-emerald-400',
      inactive: 'text-slate-500 hover:text-emerald-400 hover:bg-emerald-500/10'
    },
    charging: {
      active: 'bg-cyan-500/15 text-cyan-400',
      inactive: 'text-slate-500 hover:text-cyan-400 hover:bg-cyan-500/10'
    },
    occupied: {
      active: 'bg-orange-500/15 text-orange-400',
      inactive: 'text-slate-500 hover:text-orange-400 hover:bg-orange-500/10'
    }
  };

  // 数量徽章样式（包含响应式）
  const badgeStyles = {
    all: { active: 'bg-slate-700 text-white', inactive: 'bg-slate-800 text-slate-500' },
    free: { active: 'bg-emerald-500/20 text-emerald-300', inactive: 'bg-slate-800 text-slate-500' },
    charging: { active: 'bg-cyan-500/20 text-cyan-300', inactive: 'bg-slate-800 text-slate-500' },
    occupied: { active: 'bg-orange-500/20 text-orange-300', inactive: 'bg-slate-800 text-slate-500' }
  };

  // 更新按钮状态
  ['all', 'free', 'charging', 'occupied'].forEach(f => {
    const btn = document.getElementById(`filter-${f}`);
    const badge = btn.querySelector('span:last-child');
    const isActive = f === filter;

    // 重置类为基础类 + active 标记
    btn.className = baseClasses + (isActive ? ' active' : '');

    // 添加当前状态样式
    const styleClasses = styles[f][isActive ? 'active' : 'inactive'].split(' ');
    styleClasses.forEach(cls => btn.classList.add(cls));

    // 更新徽章样式（包含响应式）
    badge.className = 'px-1.5 md:px-2 py-0.5 rounded-full text-[10px] md:text-xs font-mono ' + badgeStyles[f][isActive ? 'active' : 'inactive'];
  });

  // 重新渲染
  if (station) {
    renderStation(station);
  }
}
