import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { api } from '../services/api'
import { selectIsAdmin } from '../store/appSlice'
import './GlobalConfig.css'
import './ConfigPanel.css' // 复用 ConfigPanel 的样式

// 复用 ConfigPanel 的 ConfigItem 组件
// 部分配置项使用“数值原样”（如 RSI 0–100、24h 涨跌幅 25 表示 25%），不做 0–1 比例转换
const NUMBER_AS_IS_KEYS = new Set([
  'MAX_RSI_FOR_LONG',
  'MIN_RSI_FOR_SHORT',
  'MAX_CHANGE_PERCENT_FOR_LONG',
  'MAX_CHANGE_PERCENT_FOR_SHORT',
])
// 配置项中文标签（便于识别）
const KEY_LABELS = {
  MAX_RSI_FOR_LONG: '做多 RSI 上限',
  MIN_RSI_FOR_SHORT: '做空 RSI 下限',
  MAX_CHANGE_PERCENT_FOR_LONG: '做多 24h 涨跌幅上限(%)',
  MAX_CHANGE_PERCENT_FOR_SHORT: '做空 24h 涨跌幅上限(%)',
  TAKE_PROFIT_1_PERCENT: '第一目标止盈(%)',
  SCAN_EXTRA_SYMBOLS_FOR_SUPPLEMENT: '智能补单候选数',
  SYMBOL_LOSS_COOLDOWN_ENABLED: '连续亏损冷却',
  SYMBOL_MAX_CONSECUTIVE_LOSSES: '连续亏损次数阈值',
  SYMBOL_LOSS_COOLDOWN_SEC: '冷却时间(秒)',
  RSI_EXTREME_REVERSE_ENABLED: 'RSI 极端反向（超买反空/超卖反多）',
  RSI_EXTREME_REVERSE_ONLY_NEUTRAL_4H: 'RSI 反向仅允许 4H 中性',
}

const ConfigItem = ({ label, config, onUpdate, disabled }) => {
  const isPercentKey = label.includes('PERCENT') || label.includes('PCT')
  const PCT_LIKE_KEYS = new Set([
    'LIMIT_ORDER_OFFSET_PCT',
    'ENTRY_MAX_DRIFT_PCT_TRENDING',
    'ENTRY_MAX_DRIFT_PCT_RANGING',
    'FIXED_RISK_PERCENT',  // 固定风险百分比，已经是小数形式（0.02 = 2%）
  ])
  const isPctLike = PCT_LIKE_KEYS.has(label)
  const isNumberAsIs = NUMBER_AS_IS_KEYS.has(label)
  const displayLabel = KEY_LABELS[label] || label

  const formatPercent = (n) => {
    if (typeof n !== 'number' || isNaN(n)) return ''
    return n.toFixed(4).replace(/\.?0+$/, '')
  }

  const getInitialDisplayValue = (val) => {
    if (config.type === 'number' && isNumberAsIs) {
      if (val === null || val === undefined || val === '') return ''
      const numVal = typeof val === 'string' ? parseFloat(val) : val
      return isNaN(numVal) ? '' : String(numVal)
    }
    if (config.type === 'number' && isPercentKey) {
      if (val === null || val === undefined || val === '') {
        return ''
      }
      const numVal = typeof val === 'string' ? parseFloat(val) : val
      if (isNaN(numVal)) {
        return ''
      }
      if (isPctLike) {
        return formatPercent(numVal <= 0.05 ? numVal * 100 : numVal)
      }
      return formatPercent(numVal <= 1 ? numVal : numVal / 100)
    }
    return val === null || val === undefined ? '' : val
  }

  const [localValue, setLocalValue] = useState(getInitialDisplayValue(config.value))
  const [isEditing, setIsEditing] = useState(false)

  useEffect(() => {
    setIsEditing(false)
    setLocalValue(getInitialDisplayValue(config.value))
  }, [config.value])

  const handleChange = (newValue) => {
    setLocalValue(newValue)
    setIsEditing(true)
  }

  const handleBlur = () => {
    if (!isEditing) return
    let finalValue = localValue
    if (config.type === 'number') {
      if (isNumberAsIs) {
        const numVal = parseFloat(localValue)
        if (isNaN(numVal)) {
          setLocalValue(getInitialDisplayValue(config.value))
          setIsEditing(false)
          return
        }
        finalValue = numVal
      } else if (isPercentKey) {
        const numVal = parseFloat(localValue)
        if (isNaN(numVal)) {
          setLocalValue(getInitialDisplayValue(config.value))
          setIsEditing(false)
          return
        }
        if (numVal < 0 || numVal > 1) {
          setLocalValue(getInitialDisplayValue(config.value))
          setIsEditing(false)
          return
        }
        finalValue = numVal
      } else {
        finalValue = parseFloat(localValue)
        if (isNaN(finalValue)) {
          setLocalValue(getInitialDisplayValue(config.value))
          setIsEditing(false)
          return
        }
      }
    } else if (config.type === 'boolean') {
      finalValue = localValue === 'true' || localValue === true
    } else {
      finalValue = localValue
    }
    onUpdate(finalValue)
    setIsEditing(false)
  }

  const displayValue = isEditing ? localValue : getInitialDisplayValue(config.value)

  return (
    <div className="config-item">
      <div className="config-item-header">
        <label>{displayLabel}</label>
      </div>
      <div className="config-input-wrapper">
        {config.type === 'boolean' ? (
          <select
            value={String(config.value || false)}
            onChange={(e) => {
              const boolValue = e.target.value === 'true'
              onUpdate(boolValue)
            }}
            disabled={disabled}
            style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
          >
            <option value="true">是</option>
            <option value="false">否</option>
          </select>
        ) : (
          <input
            type="text"
            inputMode={config.type === 'number' ? 'decimal' : 'text'}
            value={displayValue === '' ? '' : String(displayValue)}
            onChange={(e) => {
              let newValue = e.target.value
              if (config.type === 'number' && !isNumberAsIs) {
                if (isPercentKey) {
                  const numValue = parseFloat(newValue)
                  if (newValue !== '' && !isNaN(numValue) && (numValue < 0 || numValue > 1)) {
                    return
                  }
                }
              }
              handleChange(newValue)
            }}
            onBlur={handleBlur}
            onKeyDown={(e) => {
            if (e.key === 'Enter') {
              handleBlur()
            }
          }}
            disabled={disabled}
            style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
          />
        )}
        {/* ⚠️ 简化：去掉%符号，直接显示小数（0.30） */}
      </div>
      {config.description && (
        <div style={{ fontSize: '12px', color: '#666', marginTop: '4px' }}>{config.description}</div>
      )}
    </div>
  )
}

const GlobalConfig = () => {
  const isAdmin = useSelector(selectIsAdmin)
  
  const [loading, setLoading] = useState(true)
  const [message, setMessage] = useState('')
  const [busy, setBusy] = useState(false)
  // 系统控制相关
  const [systemStatus, setSystemStatus] = useState(null)
  const [backendStatus, setBackendStatus] = useState(null)
  const [servicesSummary, setServicesSummary] = useState(null)
  const [systemBusy, setSystemBusy] = useState(false)
  
  // 预设方案相关
  const [configs, setConfigs] = useState({})
  const [saving, setSaving] = useState(false)
  
  // 配置快照相关
  const [showSnapshot, setShowSnapshot] = useState(false)
  const [snapshotText, setSnapshotText] = useState('')
  const [snapshotIncludeSecrets, setSnapshotIncludeSecrets] = useState(false)
  const [snapshotBusy, setSnapshotBusy] = useState(false)
  
  // 新增：搜索和 Tab 状态
  const [searchTerm, setSearchTerm] = useState('')
  const [activeTab, setActiveTab] = useState('all')

  const PCT_LIKE_KEYS = new Set([
    'LIMIT_ORDER_OFFSET_PCT',
    'ENTRY_MAX_DRIFT_PCT_TRENDING',
    'ENTRY_MAX_DRIFT_PCT_RANGING',
  ])

  // isAdmin 已从 Redux 获取，无需重复定义

  // 预设方案配置（必须在函数定义之前，常量定义）
  const presets = {
    swing: {
      name: '波段回归（推荐）',
      desc: '根治高频与追价：关闭智能入场，回归"纯限价 + 30分钟扫描 + 更高信号门槛"的低频波段。建议先跑20-30单再评估。',
      configs: {
        SCAN_INTERVAL: 1800,
        TOP_N_SYMBOLS: 8,
        MAX_POSITION_PERCENT: 2.0,
        MAX_TOTAL_POSITION_PERCENT: 20.0,
        MIN_POSITION_PERCENT: 0.0,
        MIN_SIGNAL_STRENGTH: 8,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_HOLD_TIME_SEC: 1800,
        SMART_ENTRY_ENABLED: false,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      },
    },
    fill: {
      name: '成交优先（更少漏单）',
      desc: '优先解决"挂单NEW→超时撤单→没成交"的问题：解锁自动交易过滤 + 保守智能入场（限制追价步数与追价上限），在趋势强时允许可控的市价兜底。',
      configs: {
        SCAN_INTERVAL: 1800,
        TOP_N_SYMBOLS: 6,
        MIN_SIGNAL_STRENGTH: 7,
        AUTO_TRADE_ONLY_TRENDING: false,
        AUTO_TRADE_ALLOW_4H_NEUTRAL: true,
        SMART_ENTRY_ENABLED: true,
        LIMIT_ORDER_OFFSET_PCT: 0.1,
        ENTRY_CONFIRM_TIMEOUT_SEC: 120,
        ENTRY_CHASE_MAX_STEPS: 2,
        ENTRY_STEP_WAIT_SEC: 20,
        ENTRY_MARKET_FALLBACK_AFTER_SEC: 60,
        ENTRY_MAX_DRIFT_PCT_TRENDING: 0.3,
        ENTRY_MAX_DRIFT_PCT_RANGING: 0.15,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_HOLD_TIME_SEC: 1800,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      },
    },
    strict: {
      name: '精选低频（高胜率倾向）',
      desc: '更偏"少单、质量优先"：仅趋势行情自动交易 + 4H中性不自动下单 + 更高信号门槛。仍保持较贴近的限价偏移，减少"完全成交不了"。',
      configs: {
        SCAN_INTERVAL: 1800,
        TOP_N_SYMBOLS: 6,
        MIN_SIGNAL_STRENGTH: 8,
        AUTO_TRADE_ONLY_TRENDING: true,
        AUTO_TRADE_ALLOW_4H_NEUTRAL: false,
        SMART_ENTRY_ENABLED: false,
        LIMIT_ORDER_OFFSET_PCT: 0.1,
        ENTRY_CONFIRM_TIMEOUT_SEC: 180,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_HOLD_TIME_SEC: 1800,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      },
    },
    steady: {
      name: '稳定出单（均衡收益/频率）',
      desc: '在"会下单"的基础上略提高出单频率：更短扫描间隔 + 更宽松门槛 + 保守智能入场（追价受限），适合想要稳定有单但不想回到高频。',
      configs: {
        SCAN_INTERVAL: 900,
        TOP_N_SYMBOLS: 8,
        MIN_SIGNAL_STRENGTH: 6,
        AUTO_TRADE_ONLY_TRENDING: false,
        AUTO_TRADE_ALLOW_4H_NEUTRAL: true,
        SMART_ENTRY_ENABLED: true,
        LIMIT_ORDER_OFFSET_PCT: 0.12,
        ENTRY_CONFIRM_TIMEOUT_SEC: 120,
        ENTRY_CHASE_MAX_STEPS: 3,
        ENTRY_STEP_WAIT_SEC: 15,
        ENTRY_MARKET_FALLBACK_AFTER_SEC: 45,
        ENTRY_MAX_DRIFT_PCT_TRENDING: 0.4,
        ENTRY_MAX_DRIFT_PCT_RANGING: 0.2,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_HOLD_TIME_SEC: 1800,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      },
    },
    conservative: {
      name: '保守配置',
      desc: '适合新手，风险较低，止损止盈较宽松，避免被正常波动触发',
      configs: {
        SCAN_INTERVAL: 900,
        MIN_CHANGE_PERCENT: 2.0,
        MIN_SIGNAL_STRENGTH: 5,
        TOP_N_SYMBOLS: 10,
        MAX_SCAN_SYMBOLS: 150,
        MIN_VOLATILITY: 0.02,
        STOP_LOSS_PERCENT: 10.0,
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_STOP_LOSS_PRICE_PCT: 2.0,
        MIN_TAKE_PROFIT_PRICE_PCT: 3.0,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        MIN_HOLD_TIME_SEC: 1800,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      }
    },
    balanced: {
      name: '平衡配置',
      desc: '推荐使用，平衡频率和质量，止损止盈适中（盈亏比1.5:1）',
      configs: {
        SCAN_INTERVAL: 600,
        MIN_CHANGE_PERCENT: 1.5,
        MIN_SIGNAL_STRENGTH: 4,
        TOP_N_SYMBOLS: 12,
        MAX_SCAN_SYMBOLS: 250,
        MIN_VOLATILITY: 0.018,
        STOP_LOSS_PERCENT: 8.0,
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_STOP_LOSS_PRICE_PCT: 2.0,
        MIN_TAKE_PROFIT_PRICE_PCT: 3.0,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        MIN_HOLD_TIME_SEC: 1800,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      }
    },
    altcoin: {
      name: '山寨币狙击（高盈亏比）',
      desc: '专为山寨币设计：宽止损（2.0倍ATR+12%固定）、合理盈亏比（3:1）、移动止损保护利润、严格成交量过滤（≥3000万美元）。2026-01-27优化：让收益率真实，胜率正常化。期望胜率40%+，盈亏比1.5:1+。',
      configs: {
        // 风险控制（最关键）- 2026-01-27优化：让收益率真实，胜率正常化
        ATR_STOP_LOSS_MULTIPLIER: 1.5,  // ATR止损1.5倍（2026-01-27优化：收紧止损，减少单笔亏损）
        STOP_LOSS_PERCENT: 12.0,  // 固定止损12%（收紧止损，减少单笔亏损）
        RISK_REWARD_RATIO: 3.0,  // 盈亏比3:1（降低，更容易触发，保证胜率）
        ATR_TAKE_PROFIT_MULTIPLIER: 2.0,  // ATR止盈2.0倍（2026-01-27优化：降低止盈目标，更容易触发）
        TAKE_PROFIT_PERCENT: 20.0,  // 固定止盈20%（降低止盈目标，更容易触发，提升止盈单比例）
        MIN_HOLD_TIME_SEC: 0,  // 取消持仓锁（山寨币变化快）
        USE_FIXED_RISK_SIZING: true,  // 固定风险
        FIXED_RISK_PERCENT: 1.0,  // 每笔最多亏1%
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 不使用动态ATR
        
        // 移动止损（必须开启）- 2026-01-27优化：与第一目标止盈一致
        USE_TRAILING_STOP: true,  // 启用移动止损保护利润
        TRAILING_STOP_ACTIVATION: 20.0,  // 盈利20%后激活（与第一目标止盈一致）
        TRAILING_STOP_PROTECT: 10.0,  // 保护10%利润（给回撤足够空间）
        
        // 仓位管理
        MAX_POSITION_PERCENT: 1.5,  // 单笔1.5%（山寨币不加仓）
        MAX_TOTAL_POSITION_PERCENT: 12.0,  // 总仓位12%
        MAX_DAILY_ENTRIES: 8,  // 每日最多8笔（增加交易频率）
        MAX_OPEN_POSITIONS: 4,  // 最多4个持仓
        LEVERAGE: 8,  // 基础杠杆8倍
        MAX_LEVERAGE: 12,  // 最大杠杆12倍
        USE_DYNAMIC_LEVERAGE: false,  // 不使用动态杠杆
        
        // 品种筛选（流动性为王）
        MIN_VOLUME_24H: 30000000,  // 24H成交额≥3000万美元
        MIN_VOLUME_24H_STRICT: 50000000,  // 严格过滤≥5000万
        MIN_VOLATILITY: 3.0,  // 最小波动率3%
        TOP_N_SYMBOLS: 8,  // 选择信号最强的8个（给更多选择余地，避免错过好机会）
        MAX_SCAN_SYMBOLS: 250,  // 扫描前250个（增加覆盖率，从27.6%提升到46.0%）
        MIN_SIGNAL_STRENGTH: 5,  // 信号强度≥5（MACD金叉/死叉已足够，配合其他筛选）
        EXCLUDE_MAJOR_COINS: true,  // 排除主流币（BTC、ETH、BNB等），专注于山寨币
        
        // 时间框架
        SCAN_INTERVAL: 1800,  // 扫描间隔30分钟（增加交易机会）
        PRIMARY_INTERVAL: '4h',  // 主周期4小时
        ENTRY_INTERVAL: '1h',  // 入场周期1小时
        CONFIRM_INTERVAL: '1d',  // 确认周期日线
        
        // 智能入场
        SMART_ENTRY_ENABLED: true,  // 开启智能入场
        ENTRY_SYMBOL_COOLDOWN_SEC: 1800,  // 币种冷却30分钟
        ENTRY_MAX_DRIFT_PCT_TRENDING: 0.8,  // 追价偏离0.8%
        ENTRY_MAX_DRIFT_PCT_RANGING: 0.3,  // 震荡偏离0.3%
        
        // 交易控制
        AUTO_TRADE_ONLY_TRENDING: true,  // 只做趋势市
        AUTO_TRADE_ALLOW_4H_NEUTRAL: true,  // 允许4H中性（提高交易频率，宽止损+高盈亏比已考虑低胜率）
      },
    },
    aggressive: {
      name: '激进高频',
      desc: '晚间波动大时使用，交易频率高，止损较紧但止盈合理（盈亏比1.5:1）',
      configs: {
        SCAN_INTERVAL: 300,
        MIN_CHANGE_PERCENT: 1.0,
        MIN_SIGNAL_STRENGTH: 3,
        TOP_N_SYMBOLS: 18,
        MAX_SCAN_SYMBOLS: 350,
        MIN_VOLATILITY: 0.015,
        STOP_LOSS_PERCENT: 5.0,
        TAKE_PROFIT_PERCENT: 25.0,
        MIN_STOP_LOSS_PRICE_PCT: 1.5,
        MIN_TAKE_PROFIT_PRICE_PCT: 2.0,
        USE_TRAILING_STOP: false,
        ATR_STOP_LOSS_MULTIPLIER: 2.5,  // 放宽止损至2.5倍ATR，提升胜率
        ATR_TAKE_PROFIT_MULTIPLIER: 1.5,
        RISK_REWARD_RATIO: 1.5,  // 配合止盈倍数
        MIN_HOLD_TIME_SEC: 1800,
        USE_DYNAMIC_ATR_MULTIPLIER: false,  // 关闭动态调整，使用固定2.5倍
      }
    }
  }

  // 已知全局配置项默认值（兜底：后端未返回时前端仍能显示，避免看不到新配置项）
  const KNOWN_GLOBAL_CONFIG_DEFAULTS = {
    MAX_RSI_FOR_LONG: { value: 70, type: 'number', category: 'strategy', description: '做多时 RSI 超过此值则不开多（避免超买区追多）。2026-01-31新增。' },
    MAX_CHANGE_PERCENT_FOR_LONG: { value: 25, type: 'number', category: 'strategy', description: '做多时 24h 涨跌幅超过此值则不开多（避免追大涨）。单位：百分比数值，如 25 表示 25%。' },
    MIN_RSI_FOR_SHORT: { value: 30, type: 'number', category: 'strategy', description: '做空时 RSI 低于此值则不做空（避免深超卖反弹）。2026-01-31新增。' },
    MAX_CHANGE_PERCENT_FOR_SHORT: { value: 10, type: 'number', category: 'strategy', description: '做空时 24h 涨跌幅超过此值则不做空（24h 仍大涨时不做空）。单位：百分比数值。' },
    TAKE_PROFIT_1_PERCENT: { value: 0.15, type: 'number', category: 'strategy', description: '分步止盈第一目标（保证金百分比，如 0.15=15%）。第一目标触发后了结50%仓位。' },
    SCAN_EXTRA_SYMBOLS_FOR_SUPPLEMENT: { value: 8, type: 'number', category: 'scan', description: '智能补单：多返回的候选数量，冷却时仍可尝试后续交易对。' },
    SYMBOL_LOSS_COOLDOWN_ENABLED: { value: true, type: 'boolean', category: 'strategy', description: '是否启用同一交易对连续亏损后的冷却。' },
    SYMBOL_MAX_CONSECUTIVE_LOSSES: { value: 2, type: 'number', category: 'strategy', description: '最大允许连续亏损次数（超过则禁止交易该交易对一段时间）。' },
    SYMBOL_LOSS_COOLDOWN_SEC: { value: 3600, type: 'number', category: 'strategy', description: '连续亏损后的冷却时间（秒），默认1小时。' },
    BETA_FILTER_ENABLED: { value: true, type: 'boolean', category: 'strategy', description: '大盘共振过滤：BTC/ETH 下跌时屏蔽多单。' },
    BETA_FILTER_THRESHOLD: { value: -0.005, type: 'number', category: 'strategy', description: '大盘共振阈值（比例，如 -0.005 表示 -0.5%）。' },
    RSI_EXTREME_REVERSE_ENABLED: { value: false, type: 'boolean', category: 'strategy', description: '开启后：原信号做多但 RSI 超买(≥做多上限)时改为做空；原信号做空但 RSI 超卖(≤做空下限)时改为做多。属均值回归思路，可填补超买超卖时不下单的空置；默认关闭。' },
    RSI_EXTREME_REVERSE_ONLY_NEUTRAL_4H: { value: true, type: 'boolean', category: 'strategy', description: '建议开启：仅在 4H 趋势为中性时允许 RSI 反向单，避免在强趋势里逆势抄底/摸顶，降低风险。关闭则反向可与 4H 同向（仍受“禁止逆4H趋势”约束）。' },
  }

  const loadConfigs = async () => {
    try {
      // 管理员全局配置：从独立的全局配置表读取，不依赖任何 account
      if (isAdmin) {
        const data = await api.getGlobalConfigs()
        // 兜底：若后端未返回新配置项（如未重启），用已知默认值合并，确保前端能看到
        const merged = { ...(data || {}) }
        Object.keys(KNOWN_GLOBAL_CONFIG_DEFAULTS).forEach(key => {
          if (!(key in merged)) {
            merged[key] = KNOWN_GLOBAL_CONFIG_DEFAULTS[key]
          }
        })
        console.log('Loaded global configs:', Object.keys(merged).length, 'keys')
        setConfigs(merged)
      } else {
        // 非管理员不应该访问这个页面
        setConfigs({})
      }
    } catch (error) {
      console.error('Failed to load global configs:', error)
      setConfigs({})
    }
  }

  const loadSystemStatus = async () => {
    try {
      const res = await api.getTradingSystemStatus()
      setSystemStatus(res)
      
      try {
        const servicesRes = await api.get('/system/trading/services')
        setServicesSummary(servicesRes.data.summary)
      } catch (e) {
        // Services summary failed
      }
    } catch (error) {
      // 静默失败
    }
  }

  const loadBackendStatus = async () => {
    try {
      const res = await api.getBackendStatus()
      setBackendStatus(res)
    } catch (error) {
      // 静默失败
    }
  }

  useEffect(() => {
    const init = async () => {
      if (isAdmin) {
        // 加载全局配置（独立于账户）
        await Promise.allSettled([
          loadConfigs(),
          loadSystemStatus(),
          loadBackendStatus()
        ])
      }
      setLoading(false)
    }
    init()

    // 只有管理员才轮询系统状态
    if (isAdmin) {
      const timer = setInterval(() => {
        loadSystemStatus().catch(() => {})
        loadBackendStatus().catch(() => {})
      }, 3000)
      return () => clearInterval(timer)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAdmin])

  // 系统控制函数
  const handleClearCache = async () => {
    setSystemBusy(true)
    setMessage('')
    try {
      const res = await api.clearSystemCache()
      setMessage(res.message || '缓存已清理')
      await loadConfigs()
      await loadSystemStatus()
    } catch (error) {
      setMessage('清理缓存失败: ' + (error.message || '未知错误'))
    } finally {
      setSystemBusy(false)
    }
  }

  const handleStopBackend = async () => {
    if (!window.confirm('警告：确定要停止后端服务吗？\n\n停止后 Web 界面将立即无法访问！\n必须手动登录服务器执行 ./start.sh 才能恢复。')) return
    setSystemBusy(true)
    setMessage('')
    try {
      const res = await api.stopBackend()
      setMessage(res.message || '后端服务已停止')
      alert('后端服务已停止，页面将不再响应。请手动去服务器启动。')
    } catch (error) {
      setMessage('停止后端失败: ' + (error.message || '未知错误'))
    } finally {
      setSystemBusy(false)
    }
  }

  const handleRestartBackend = async () => {
    if (!window.confirm('确定要重启后端服务吗？重启期间页面接口会短暂不可用（约 3-10 秒）。')) return
    setSystemBusy(true)
    setMessage('')
    try {
      const res = await api.restartBackend()
      setMessage(res.message || '已发起后端重启')
      setTimeout(() => {
        loadBackendStatus()
      }, 4000)
    } catch (error) {
      setMessage('重启后端失败: ' + (error.message || '未知错误'))
    } finally {
      setSystemBusy(false)
    }
  }

  const handleRestartAllTrading = async () => {
    if (!window.confirm('确定要重启【所有账号】的交易进程吗？这会让所有用户的交易服务短暂中断（约 3-10 秒），用于升级代码后统一生效。')) return
    setSystemBusy(true)
    setMessage('')
    try {
      const res = await api.restartAllTradingSystems({ prefix: 'auto_sys_acc', do_update: true })
      setMessage(`已发起批量重启：共 ${res.count} 个，成功 ${res.ok}，失败 ${res.failed}`)
    } catch (e) {
      setMessage('批量重启失败: ' + (e?.message || '未知错误'))
    } finally {
      setSystemBusy(false)
    }
  }

  const handleStopAllTrading = async () => {
    if (!window.confirm('确定要停止【所有账号】的交易进程吗？所有账号将停止自动交易！')) return
    setSystemBusy(true)
    setMessage('')
    try {
      const res = await api.stopAllTradingSystems({ prefix: 'auto_sys_acc', include_default: true })
      setMessage(`已发起批量停止：共 ${res.count} 个，成功 ${res.ok}，失败 ${res.failed}`)
      await loadSystemStatus()
    } catch (e) {
      setMessage('批量停止失败: ' + (e?.message || '未知错误'))
    } finally {
      setSystemBusy(false)
    }
  }


  const applyPreset = async (presetKey) => {
    const preset = presets[presetKey]
    if (!preset) return

    setSaving(true)
    setMessage('')
    try {
      const configItems = Object.entries(preset.configs).map(([key, value]) => {
        const config = configs[key]
        if (!config) {
          let type = 'number'
          let category = 'risk'
          if (typeof value === 'boolean') {
            type = 'boolean'
            category = 'strategy'
          }
          if (key.startsWith('ENTRY_') || key.startsWith('SMART_ENTRY_') || key === 'SMART_ENTRY_ENABLED') {
            type = typeof value === 'boolean' ? 'boolean' : 'number'
            category = 'strategy'
          } else if (key.startsWith('AUTO_TRADE_')) {
            type = typeof value === 'boolean' ? 'boolean' : 'number'
            category = 'strategy'
          } else if (key === 'LIMIT_ORDER_OFFSET_PCT') {
            type = 'number'
            category = 'strategy'
          } else if (key.includes('PERCENT') || key.includes('PCT')) {
            type = 'number'
            if (key.includes('STOP_LOSS') || key.includes('TAKE_PROFIT')) {
              category = 'risk'
            } else if (key.includes('POSITION')) {
              category = 'position'
            } else {
              category = 'scan'
            }
          } else if (key === 'MIN_VOLATILITY') {
            type = 'number'
            category = 'scan'
          } else if (typeof value === 'number') {
            type = 'number'
            category = 'scan'
          }

          return {
            key,
            value: (key.includes('PERCENT') || key.includes('PCT')) && !PCT_LIKE_KEYS.has(key) ? value / 100 : value,
            type,
            category,
            description: `预设方案配置项：${key}`
          }
        }
        return {
          key,
          value: (key.includes('PERCENT') || key.includes('PCT')) && !PCT_LIKE_KEYS.has(key) ? value / 100 : value,
          type: config.type,
          category: config.category,
          description: config.description
        }
      }).filter(Boolean)

      // 管理员全局配置：使用独立的全局配置API
      let response
      if (isAdmin) {
        response = await api.updateGlobalConfigsBatch(configItems)
      } else {
        // 非管理员不应该访问这个页面，但为了安全还是处理一下
        throw new Error('只有管理员可以修改全局配置')
      }
      setMessage(response.message || `已应用${preset.name}`)
      if (response.note) {
        setTimeout(() => {
          setMessage(response.note)
        }, 2000)
      }
      await loadConfigs()
    } catch (error) {
      setMessage('应用预设失败: ' + error.message)
    } finally {
      setSaving(false)
    }
  }

  // 单个配置更新（带确认）
  const handleConfigUpdate = async (key, value, config) => {
    // 检查是否有实质变化
    if (config.value === value) return

    // 格式化显示值用于确认弹窗
    let displayOld = config.value
    let displayNew = value
    
    // 如果是百分比相关的，尝试转回百分数显示，更直观
    const isPercent = key.includes('PERCENT') || key.includes('PCT')
    if (isPercent && typeof value === 'number' && Math.abs(value) <= 1) {
       // 简单判断：如果原值是小数且 key 含 PERCENT，可能是小数存储。
       // 这里为了保险，直接显示原始值和新值，管理员自己判断。
       // 或者简单转一下
       displayOld = `${config.value} (${(config.value * 100).toFixed(2)}%)`
       displayNew = `${value} (${(value * 100).toFixed(2)}%)`
    }

    const confirmMsg = `确定修改配置项【${key}】吗？\n\n原值: ${displayOld}\n新值: ${displayNew}\n\n修改将立即生效。`
    if (!window.confirm(confirmMsg)) {
      // 如果用户取消，理论上 UI 应该回滚。
      // 但 ConfigItem 内部状态已经变了（onBlur 触发）。
      // 触发一次重载配置可以强制 UI 回滚
      await loadConfigs()
      return
    }

    try {
      setSaving(true)
      setMessage('')
      if (!isAdmin) {
        setMessage('只有管理员可以修改全局配置')
        return
      }
      await api.updateGlobalConfigsBatch([{
        key,
        value,
        type: config.type,
        category: config.category,
        description: config.description
      }])
      setMessage(`已更新 ${key}`)
      await loadConfigs()
    } catch (error) {
      setMessage('更新配置失败: ' + error.message)
    } finally {
      setSaving(false)
    }
  }

  // 配置快照函数
  const isSecretKey = (key) => {
    return key === 'BINANCE_API_KEY' || key === 'BINANCE_API_SECRET'
  }

  const maskSecret = (val) => {
    const s = val === null || val === undefined ? '' : String(val)
    if (!s) return ''
    if (s.length <= 8) return '****'
    return `${s.slice(0, 4)}...${s.slice(-4)}`
  }

  const toDisplayValueForSnapshot = (key, value) => {
    if (value === null || value === undefined) return value
    if (typeof value === 'number' && (key.includes('PERCENT') || key.includes('PCT'))) {
      if (PCT_LIKE_KEYS.has(key)) {
        return value <= 0.05 ? value * 100 : value
      }
      return value < 1 ? value * 100 : value
    }
    return value
  }

  const buildConfigSnapshot = async (includeSecrets) => {
    // 管理员全局配置：从独立的全局配置表读取
    let data
    if (isAdmin) {
      data = await api.getGlobalConfigs()
    } else {
      data = await api.getConfigs()
    }
    const now = new Date()

    const categoryMap = {
      scan: '市场扫描',
      position: '仓位控制',
      risk: '风险控制',
      strategy: '策略参数',
      api: 'API配置',
    }

    const entries = Object.entries(data || {}).map(([key, cfg]) => {
      const rawVal = cfg?.value
      const valMasked = isSecretKey(key) && !includeSecrets ? maskSecret(rawVal) : rawVal
      const displayVal = toDisplayValueForSnapshot(key, valMasked)
      return {
        key,
        category: cfg?.category || '',
        category_label: categoryMap[cfg?.category] || cfg?.category || '',
        type: cfg?.type || '',
        value: valMasked,
        display_value: displayVal,
        description: cfg?.description || '',
      }
    })

    entries.sort((a, b) => {
      const ca = a.category_label || a.category || ''
      const cb = b.category_label || b.category || ''
      if (ca !== cb) return ca.localeCompare(cb)
      return a.key.localeCompare(b.key)
    })

    // 临时获取当前配置以检测预设
    const tempConfigs = data || {}
    let detectedPreset = null
    for (const [presetKey, preset] of Object.entries(presets)) {
      let match = true
      for (const [key, expectedValue] of Object.entries(preset.configs)) {
        const currentConfig = tempConfigs[key]
        if (!currentConfig) {
          match = false
          break
        }
        let currentValue = currentConfig.value
        if (key.includes('PERCENT') || key.includes('PCT')) {
          if (PCT_LIKE_KEYS.has(key)) {
            currentValue = currentValue <= 0.05 ? currentValue * 100 : currentValue
          } else {
            currentValue = currentValue * 100
          }
        }
        if (typeof expectedValue === 'number' && typeof currentValue === 'number') {
          if (Math.abs(currentValue - expectedValue) > 0.01) {
            match = false
            break
          }
        } else if (currentValue !== expectedValue) {
          match = false
          break
        }
      }
      if (match) {
        detectedPreset = presetKey
        break
      }
    }

    const snapshot = {
      fetched_at: now.toISOString(),
      note: 'display_value 对 PERCENT/PCT 做了百分比换算；敏感字段可选择脱敏/明文。',
      preset_detected: detectedPreset,
      system_status: systemStatus ? {
        running: !!systemStatus.running,
        pid: systemStatus.pid || null,
        program: systemStatus.program || null,
        state: systemStatus.state || null,
      } : null,
      configs: entries,
    }

    return JSON.stringify(snapshot, null, 2)
  }

  const openSnapshot = async (includeSecrets) => {
    setSnapshotBusy(true)
    setMessage('')
    try {
      const text = await buildConfigSnapshot(includeSecrets)
      setSnapshotText(text)
      setShowSnapshot(true)
    } catch (e) {
      setMessage('生成配置快照失败: ' + (e?.message || '未知错误'))
    } finally {
      setSnapshotBusy(false)
    }
  }

  const copySnapshot = async () => {
    try {
      if (navigator?.clipboard?.writeText) {
        await navigator.clipboard.writeText(snapshotText || '')
        setMessage('已复制配置快照到剪贴板')
      } else {
        setMessage('当前浏览器不支持剪贴板 API，可手动全选复制')
      }
    } catch (e) {
      setMessage('复制失败: ' + (e?.message || '未知错误'))
    }
  }

  const downloadSnapshot = () => {
    try {
      const blob = new Blob([snapshotText || ''], { type: 'application/json;charset=utf-8' })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = `config-snapshot-${new Date().toISOString().replace(/[:.]/g, '-')}.json`
      document.body.appendChild(a)
      a.click()
      a.remove()
      URL.revokeObjectURL(url)
    } catch (e) {
      setMessage('下载失败: ' + (e?.message || '未知错误'))
    }
  }


  const loadUsersAndAccounts = async () => {
    if (!isAdmin) return
    try {
      setBusy(true)
      const [users, accounts] = await Promise.all([
        api.getUsersDetailed ? api.getUsersDetailed() : api.get('/admin/users/detailed').then(r => r.data),
        api.getAccounts(),
      ])
      setUsersDetailed(Array.isArray(users) ? users : [])
      setAccountsAdmin(Array.isArray(accounts) ? accounts : [])
      const initMap = {}
      ;(Array.isArray(users) ? users : []).forEach(u => {
        initMap[u.id] = ''
      })
      setLinkAccountMap(initMap)
    } catch (e) {
      setMessage(e?.message || '加载失败')
    } finally {
      setBusy(false)
    }
  }

  useEffect(() => {
    if (isAdmin) loadUsersAndAccounts()
  }, [isAdmin])

  if (loading) {
    return <div className="global-config">加载中...</div>
  }

  // 管理员全局配置页面：不依赖任何 account，直接管理全局配置表
  const isGlobalStrategyAccount = isAdmin
  
  // 简单计算：当前预设（直接在 render 时计算，不使用 useMemo）
  let currentPreset = null
  if (configs && Object.keys(configs).length > 0 && presets) {
    try {
      // 直接内联检测逻辑，避免函数调用
      for (const [presetKey, preset] of Object.entries(presets)) {
        let match = true
        for (const [key, expectedValue] of Object.entries(preset.configs)) {
          const currentConfig = configs[key]
          if (!currentConfig) {
            match = false
            break
          }
          let currentValue = currentConfig.value
          if (key.includes('PERCENT') || key.includes('PCT')) {
            if (PCT_LIKE_KEYS.has(key)) {
              currentValue = currentValue <= 0.05 ? currentValue * 100 : currentValue
            } else {
              currentValue = currentValue * 100
            }
          }
          if (typeof expectedValue === 'number' && typeof currentValue === 'number') {
            if (Math.abs(currentValue - expectedValue) > 0.01) {
              match = false
              break
            }
          } else if (currentValue !== expectedValue) {
            match = false
            break
          }
        }
        if (match) {
          currentPreset = presetKey
          break
        }
      }
    } catch (e) {
      console.error('detectCurrentPreset error:', e)
    }
  }

  const presetUiMeta = {
    altcoin: { group: 'altcoin', tag: '山寨币专用' },
    swing: { group: 'limit', tag: '纯限价' },
    strict: { group: 'limit', tag: '纯限价' },
    fill: { group: 'smart', tag: '智能入场' },
    steady: { group: 'smart', tag: '智能入场' },
    conservative: { group: 'legacy', tag: '传统' },
    balanced: { group: 'legacy', tag: '传统' },
    aggressive: { group: 'legacy', tag: '高频实验' },
  }

  const presetGroups = [
    {
      key: 'altcoin',
      title: '⭐ 山寨币高盈亏比狙击策略',
      desc: '专为山寨币设计：宽止损（2.0×ATR）+ 高盈亏比（4:1）+ 移动止损 + 严格流动性筛选。目标胜率35%，期望值+0.75%/笔。',
      presetKeys: ['altcoin'],
    },
    {
      key: 'limit',
      title: 'A. 纯限价（SMART_ENTRY_ENABLED=false）',
      desc: '只下 1 次限价单，未在确认时间内成交就撤单跳过。更控频、更接近"波段"，但更容易出现 NEW→撤单。',
      presetKeys: ['swing', 'strict'],
    },
    {
      key: 'smart',
      title: 'B. 智能入场（SMART_ENTRY_ENABLED=true）',
      desc: '限价回调 + 受限追价 +（趋势强时）可控市价兜底。更少漏单，但必须限制追价步数与偏离上限，避免回到高频追价。',
      presetKeys: ['fill', 'steady'],
    },
    {
      key: 'legacy',
      title: 'C. 传统 / 实验（不建议长期）',
      desc: '这组更多用于对比或临时实验（频率更高/更容易过度交易），建议在稳定盈利前谨慎使用。',
      presetKeys: ['conservative', 'balanced', 'aggressive'],
    },
  ]



  const handleGrant = async (userId) => {
    const aid = parseInt(String(linkAccountMap[userId] || ''), 10)
    if (!Number.isFinite(aid) || aid <= 0) return
    try {
      setBusy(true)
      await api.grantUserAccount(userId, aid, linkRole)
      setMessage('已关联账号')
      await loadUsersAndAccounts()
    } catch (e) {
      setMessage(e?.message || '关联失败')
    } finally {
      setBusy(false)
    }
  }
  const handleRevoke = async (userId, accountId) => {
    try {
      setBusy(true)
      await api.revokeUserAccount(userId, accountId)
      setMessage('已取消关联')
      await loadUsersAndAccounts()
    } catch (e) {
      setMessage(e?.message || '取消失败')
    } finally {
      setBusy(false)
    }
  }

  return (
    <div className="global-config">
      <div className="global-config-header">
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div>
            <h2>全局配置</h2>
            <p>管理用户、账号和全局策略配置</p>
          </div>
          <div style={{ display: 'flex', gap: '12px' }}>
            <button
              type="button"
              className="guide-link snapshot-btn"
              onClick={() => openSnapshot(snapshotIncludeSecrets)}
              disabled={snapshotBusy}
              title="导出当前全量配置（用于分析）"
            >
              {snapshotBusy ? '生成中...' : '查看整体配置'}
            </button>
            <Link to="/config/guide" className="guide-link">📖 配置说明</Link>
          </div>
        </div>
      </div>

      {message && (
        <div className={`message ${message.includes('失败') ? 'error' : 'success'}`}>
          {message}
        </div>
      )}

      {/* 系统控制 */}
      {isAdmin && (
        <section className="global-section system-section">
          <div className="system-header">
            <h3>系统控制</h3>
            <div className="system-status-indicators" style={{ display: 'flex', gap: '15px', fontSize: '14px', alignItems: 'center', marginLeft: '20px' }}>
               <div className="status-item" style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
                  <span style={{ width: '10px', height: '10px', borderRadius: '50%', backgroundColor: backendStatus?.running ? '#4caf50' : '#f44336', display: 'inline-block' }}></span>
                  <span style={{ fontWeight: 500 }}>后端: {backendStatus?.running ? '运行中' : '停止'}</span>
               </div>
               {servicesSummary && (
                 <div className="status-item" style={{ display: 'flex', alignItems: 'center', gap: '6px', borderLeft: '1px solid #ddd', paddingLeft: '15px' }}>
                    <span style={{ width: '10px', height: '10px', borderRadius: '50%', backgroundColor: '#2196f3', display: 'inline-block' }}></span>
                    <span style={{ fontWeight: 500 }}>交易服务: </span>
                    <span style={{ fontWeight: 'bold' }}>{servicesSummary.total}</span>
                    <span style={{ color: '#666' }}>个</span>
                    <span style={{ color: '#4caf50', marginLeft: '8px', fontSize: '0.9em' }}>● 运行 {servicesSummary.running}</span>
                    <span style={{ color: '#f44336', marginLeft: '8px', fontSize: '0.9em' }}>● 停止 {servicesSummary.stopped}</span>
                    {servicesSummary.unknown > 0 && <span style={{ color: '#999', marginLeft: '8px', fontSize: '0.9em' }}>● 未知 {servicesSummary.unknown}</span>}
                 </div>
               )}
            </div>
          </div>
          
          <div className="system-control-group">
            <h4 className="control-group-title" style={{ margin: '10px 0 8px', fontSize: '14px', color: '#666' }}>后端服务管理</h4>
            <div className="system-actions">
              <button
                type="button"
                className="system-btn primary"
                onClick={handleRestartBackend}
                disabled={systemBusy}
                title="通过 backend/restart.sh 重启后端（uvicorn）。重启期间接口会短暂不可用。"
              >
                重启后端服务
              </button>
              <button
                type="button"
                className="system-btn danger"
                onClick={handleStopBackend}
                disabled={systemBusy}
                title="停止后端服务（需要手动去服务器启动）"
              >
                停止后端服务
              </button>
            </div>
          </div>

          <div className="system-control-group" style={{ marginTop: '15px' }}>
            <h4 className="control-group-title" style={{ margin: '10px 0 8px', fontSize: '14px', color: '#666' }}>系统数据维护</h4>
            <div className="system-actions">
              <button
                type="button"
                className="system-btn warning"
                onClick={handleClearCache}
                disabled={systemBusy}
                title="清理Redis配置缓存并从数据库回灌。这将影响后端服务和所有交易进程。切换API Key或修改配置后建议执行。"
              >
                清除全局缓存
              </button>
              <span style={{ fontSize: '12px', color: '#888', alignSelf: 'center', marginLeft: '10px' }}>
                * 影响后端服务及所有交易账号，修改配置后请点击。
              </span>
            </div>
          </div>

          <div className="system-control-group" style={{ marginTop: '15px' }}>
            <h4 className="control-group-title" style={{ margin: '10px 0 8px', fontSize: '14px', color: '#666' }}>交易服务管理</h4>
            <div className="system-actions">
              <button
                type="button"
                className="system-btn primary"
                onClick={handleRestartAllTrading}
                disabled={systemBusy}
                title="批量重启所有账号交易进程（auto_sys_acc*），用于代码升级后统一生效"
              >
                重启所有账号交易
              </button>
              <button
                type="button"
                className="system-btn danger"
                onClick={handleStopAllTrading}
                disabled={systemBusy}
                title="批量停止所有账号交易进程（auto_sys_acc*）"
              >
                停止所有账号交易
              </button>
            </div>
          </div>

          <div className="system-hint">
            建议流程：先更新配置里的 Key → 点击"清除缓存" → 点击"重启所有账号交易"，确保不再使用旧账号下单。
          </div>
        </section>
      )}







      {/* 预设方案快速切换（仅管理员 + 全局策略账号） */}
      {isAdmin && isGlobalStrategyAccount && (
        <section className="global-section preset-section">
          <div className="preset-header">
            <h3>快速切换方案</h3>
            <div className="current-preset-status">
              <span className="status-label">当前方案：</span>
              <span className={`status-badge ${currentPreset ? 'preset' : 'custom'}`}>
                {currentPreset && presets && presets[currentPreset] ? presets[currentPreset].name : '自定义'}
              </span>
            </div>
          </div>
          <div className="preset-guide">
            <div className="preset-guide-title">怎么选更不迷糊</div>
            <ul className="preset-guide-list">
              <li>
                <strong>先选入场机制</strong>：纯限价（更控频但可能撤单） vs 智能入场（更少漏单但需限制追价）。
              </li>
              <li>
                <strong>再看"会不会下单"</strong>：如果你发现几乎不出单，优先把 <code>AUTO_TRADE_ONLY_TRENDING</code> 关掉、把 <code>AUTO_TRADE_ALLOW_4H_NEUTRAL</code> 打开。
              </li>
              <li>
                <strong>最后再微调</strong>：想更容易成交 → 调小 <code>LIMIT_ORDER_OFFSET_PCT</code>、调大 <code>ENTRY_CONFIRM_TIMEOUT_SEC</code>。
              </li>
            </ul>
          </div>

          <div className="preset-groups">
            {presetGroups.map((g) => (
              <div key={g.key} className="preset-group">
                <div className="preset-group-header">
                  <div className="preset-group-title">{g.title}</div>
                  <div className="preset-group-desc">{g.desc}</div>
                </div>
                <div className="preset-buttons">
                  {g.presetKeys
                    .filter((k) => presets && presets[k])
                    .map((k) => {
                      const preset = presets && presets[k] ? presets[k] : null
                      if (!preset) return null
                      const meta = presetUiMeta && presetUiMeta[k] ? presetUiMeta[k] : { group: g.key, tag: '' }
                      return (
                        <button
                          key={k}
                          className={`preset-btn ${currentPreset === k ? 'active' : ''}`}
                          onClick={() => {
                            if (typeof applyPreset === 'function') {
                              applyPreset(k)
                            }
                          }}
                          disabled={saving}
                          title={preset.desc}
                        >
                          <div className="preset-name">
                            {preset.name}
                            {meta.tag ? (
                              <span className={`preset-tag preset-tag--${meta.group}`}>{meta.tag}</span>
                            ) : null}
                            {currentPreset === k ? <span className="active-indicator">✓</span> : null}
                          </div>
                          <div className="preset-desc">{preset.desc}</div>
                        </button>
                      )
                    })
                    .filter(Boolean)}
                </div>
              </div>
            ))}
          </div>
        </section>
      )}

      {/* 全局策略配置项编辑（仅管理员） */}
      {isAdmin && (
        <section className="global-section config-section">
          <div className="section-header">
            <h3>全局策略配置</h3>
            <p style={{ fontSize: '14px', color: '#666', marginTop: '8px' }}>
              修改全局策略配置，所有普通用户账号将使用这些配置（风险旋钮除外）
            </p>
          </div>

          {/* 搜索和筛选栏 */}
          <div className="config-toolbar" style={{ marginBottom: '20px', display: 'flex', flexDirection: 'column', gap: '15px' }}>
            {/* 搜索框 */}
            <div className="search-bar" style={{ display: 'flex', alignItems: 'center', position: 'relative' }}>
              <input
                type="text"
                placeholder="🔍 搜索配置项 Key、描述或中文名..."
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                style={{
                  width: '100%',
                  padding: '10px 12px',
                  borderRadius: '6px',
                  border: '1px solid #ddd',
                  fontSize: '14px'
                }}
              />
              {searchTerm && (
                <button
                  onClick={() => setSearchTerm('')}
                  style={{ 
                    position: 'absolute',
                    right: '10px',
                    border: 'none', 
                    background: 'none', 
                    cursor: 'pointer', 
                    color: '#999',
                    fontSize: '16px'
                  }}
                >
                  ✕
                </button>
              )}
            </div>

            {/* Tabs */}
            <div className="config-tabs" style={{ display: 'flex', gap: '10px', overflowX: 'auto', paddingBottom: '5px' }}>
              {[
                { key: 'all', label: '全部' },
                { key: 'risk', label: '风险控制' },
                { key: 'strategy', label: '策略参数' },
                { key: 'scan', label: '市场扫描' },
                { key: 'position', label: '仓位控制' },
              ].map(tab => (
                <button
                  key={tab.key}
                  onClick={() => setActiveTab(tab.key)}
                  className={`tab-btn ${activeTab === tab.key ? 'active' : ''}`}
                  style={{
                    padding: '8px 16px',
                    borderRadius: '20px',
                    border: activeTab === tab.key ? '1px solid #007bff' : '1px solid #eee',
                    background: activeTab === tab.key ? '#e7f1ff' : '#f9f9f9',
                    color: activeTab === tab.key ? '#007bff' : '#666',
                    cursor: 'pointer',
                    fontWeight: activeTab === tab.key ? '600' : 'normal',
                    whiteSpace: 'nowrap',
                    transition: 'all 0.2s'
                  }}
                >
                  {tab.label}
                </button>
              ))}
            </div>
          </div>

          {Object.keys(configs).length > 0 ? (
            (() => {
              const configCategories = {
                'risk': '风险控制',
                'strategy': '策略参数',
                'scan': '市场扫描',
                'position': '仓位控制',
              }

              // 过滤逻辑
              const filteredConfigs = Object.entries(configs).filter(([key, config]) => {
                // 1. 基础过滤（排除非对象、风险旋钮、API Key）
                if (!config || typeof config !== 'object') return false
                const RISK_KNOBS_KEYS = ['MIN_MARGIN_USDT', 'MIN_POSITION_PERCENT', 'MAX_POSITION_PERCENT', 
                  'MAX_TOTAL_POSITION_PERCENT', 'AUTO_TRADE_ENABLED', 'MAX_OPEN_POSITIONS', 'MAX_DAILY_ENTRIES']
                if (RISK_KNOBS_KEYS.includes(key)) return false
                if (key === 'BINANCE_API_KEY' || key === 'BINANCE_API_SECRET' || key === 'USE_TESTNET') return false

                // 2. Tab 过滤
                if (activeTab !== 'all' && config.category !== activeTab) return false

                // 3. 搜索过滤
                if (searchTerm) {
                  const lowerTerm = searchTerm.toLowerCase()
                  const matchKey = key.toLowerCase().includes(lowerTerm)
                  const matchDesc = (config.description || '').toLowerCase().includes(lowerTerm)
                  const matchLabel = (KEY_LABELS[key] || '').toLowerCase().includes(lowerTerm)
                  if (!matchKey && !matchDesc && !matchLabel) return false
                }

                return true
              })

              if (filteredConfigs.length === 0) {
                 return <div style={{ textAlign: 'center', color: '#999', padding: '30px', background: '#f5f5f5', borderRadius: '8px' }}>未找到匹配的配置项</div>
              }

              // 分组渲染
              // 如果是 'all' Tab，按 Category 分组
              // 如果是特定 Tab，直接渲染（或者也分组，只有一个组）
              const groupsToRender = activeTab === 'all' 
                ? Object.keys(configCategories) 
                : [activeTab]

              // 将 filteredConfigs 转为 Map 或方便查找的结构，或者每次 filter
              
              return groupsToRender.map(category => {
                const categoryLabel = configCategories[category] || category
                const groupConfigs = filteredConfigs.filter(([_, cfg]) => cfg.category === category)
                
                if (groupConfigs.length === 0) return null

                return (
                  <div key={category} style={{ marginBottom: '24px' }}>
                    <h4 style={{ marginBottom: '12px', fontSize: '16px', fontWeight: '600', borderLeft: '4px solid #007bff', paddingLeft: '10px', color: '#333' }}>
                      {categoryLabel}
                    </h4>
                    <div className="config-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: '16px' }}>
                      {groupConfigs.map(([key, config]) => (
                        <ConfigItem
                          key={key}
                          label={key}
                          config={config}
                          onUpdate={(val) => handleConfigUpdate(key, val, config)}
                          disabled={saving}
                        />
                      ))}
                    </div>
                  </div>
                )
              })
            })()
          ) : (
            <div style={{ padding: '20px', textAlign: 'center', color: '#666' }}>
              {loading ? '加载配置中...' : '暂无配置项'}
            </div>
          )}
        </section>
      )}





      {/* 配置快照 Modal */}
      {showSnapshot && (
        <div className="snapshot-modal-overlay" onClick={() => setShowSnapshot(false)} role="presentation">
          <div className="snapshot-modal" onClick={(e) => e.stopPropagation()}>
            <div className="snapshot-modal-header">
              <div>
                <h3>当前整体配置快照</h3>
                <div className="snapshot-hint">
                  默认脱敏 BINANCE_API_KEY/SECRET。你可以选择明文后重新生成再复制/下载。
                </div>
              </div>
              <button type="button" className="snapshot-close" onClick={() => setShowSnapshot(false)}>
                关闭
              </button>
            </div>

            <div className="snapshot-toolbar">
              <label className="snapshot-checkbox">
                <input
                  type="checkbox"
                  checked={snapshotIncludeSecrets}
                  onChange={async (e) => {
                    const checked = e.target.checked
                    setSnapshotIncludeSecrets(checked)
                    await openSnapshot(checked)
                  }}
                />
                显示敏感信息（明文）
              </label>

              <div className="snapshot-actions">
                <button type="button" className="system-btn" onClick={copySnapshot}>
                  复制
                </button>
                <button type="button" className="system-btn primary" onClick={downloadSnapshot}>
                  下载 JSON
                </button>
              </div>
            </div>

            <pre className="snapshot-pre">{snapshotText}</pre>
          </div>
        </div>
      )}
    </div>
  )
}

export default GlobalConfig
