/** 畜牧资源大屏 ECharts 配置（对齐 doc/大屏/畜牧资源 技术方案） */
import 'echarts-wordcloud'
import { buildMallPie2DOption } from '@/utils/mallPie2d'

const AXIS_LABEL = { color: '#9fb0c3', fontSize: 10 }
const AXIS_LINE = { lineStyle: { color: 'rgba(61, 217, 176, 0.35)' } }
const SPLIT_LINE = { lineStyle: { color: 'rgba(61, 217, 176, 0.12)' } }
const GRID = { left: 40, right: 16, top: 36, bottom: 28, containLabel: true }

const PIE_COLORS = ['#5ef0c8', '#ecd27b', '#6eb5ff', '#0f8f72', '#8a9fb0']
const BAR_COLORS = ['#5ef0c8', '#ecd27b', '#6eb5ff', '#98e9aa']
const WORD_COLORS = ['#5ef0c8', '#98e9aa', '#ecd27b', '#6eb5ff', '#a8d4c8', '#0f8f72']

function emptyOption(text = '暂无数据') {
  return {
    title: {
      text,
      left: 'center',
      top: 'middle',
      textStyle: { color: '#6a9f90', fontSize: 13, fontWeight: 'normal' }
    }
  }
}

function formatShortDate(dateStr) {
  if (!dateStr) {
    return ''
  }
  const parts = String(dateStr).split('-')
  if (parts.length >= 3) {
    return `${parts[1]}-${parts[2]}`
  }
  return dateStr
}

function toNum(val) {
  const n = Number(val)
  return Number.isNaN(n) ? 0 : n
}

function chartBase() {
  return { title: { show: false } }
}

/** 科技特派员 — 内外双层饼：内层男女，外层党员/其他 */
export function buildTechEnvoyStructureOption(techEnvoyStructure) {
  const partyShare = techEnvoyStructure?.partyShare || []
  const genderShare = techEnvoyStructure?.genderShare || []
  const partyTotal = partyShare.reduce((sum, item) => sum + toNum(item.count), 0)
  const genderTotal = genderShare.reduce((sum, item) => sum + toNum(item.count), 0)
  if (partyTotal <= 0 && genderTotal <= 0) {
    return emptyOption('暂无特派员数据')
  }

  const partyColor = {
    PARTY: '#5ef0c8',
    OTHER: '#ecd27b'
  }
  const genderColor = {
    MALE: '#6eb5ff',
    FEMALE: '#98e9aa'
  }

  const outerData = partyShare.map((item) => {
    const code = item.itemCode || ''
    const color = partyColor[code] || '#5ef0c8'
    return {
      name: item.itemName || code || '未知',
      value: toNum(item.count),
      ratio: item.ratio,
      itemStyle: { color },
      label: { color },
      labelLine: { lineStyle: { color } }
    }
  })
  const innerData = genderShare.map((item) => {
    const code = item.itemCode || ''
    return {
      name: item.itemName || code || '未知',
      value: toNum(item.count),
      ratio: item.ratio,
      itemStyle: { color: genderColor[code] || '#6eb5ff' }
    }
  })

  const pieBorder = {
    borderColor: 'rgba(8, 48, 42, 0.88)',
    borderWidth: 2
  }

  return {
    ...chartBase(),
    tooltip: {
      trigger: 'item',
      formatter: (p) => {
        const ratio =
          p.data?.ratio != null ? `${Number(p.data.ratio).toFixed(1)}%` : `${p.percent?.toFixed(1)}%`
        return `${p.seriesName}<br/>${p.marker}${p.name}: ${p.value ?? 0} 人 (${ratio})`
      }
    },
    legend: {
      show: false
    },
    series: [
      // 外环：党员 / 其他
      {
        name: '政治面貌',
        type: 'pie',
        radius: ['58%', '74%'],
        center: ['50%', '52%'],
        avoidLabelOverlap: true,
        itemStyle: pieBorder,
        label: {
          show: true,
          fontSize: 11,
          formatter: (p) => p.name
        },
        labelLine: {
          show: true,
          length: 10,
          length2: 12
        },
        data: outerData
      },
      // 内饼：男性 / 女性
      {
        name: '性别',
        type: 'pie',
        radius: [0, '46%'],
        center: ['50%', '52%'],
        avoidLabelOverlap: true,
        itemStyle: pieBorder,
        label: {
          show: true,
          position: 'inside',
          color: '#fff',
          fontSize: 12,
          fontWeight: 600,
          formatter: (p) => p.name
        },
        labelLine: { show: false },
        data: innerData
      }
    ]
  }
}

/** 活跃度趋势 — 7 日会话数 + 提问量堆叠面积图 */
export function buildActivityTrendOption(activityTrend) {
  const series = activityTrend?.dailySeries || []
  if (!series.length) {
    return emptyOption('暂无活跃数据')
  }
  const dates = series.map((d) => formatShortDate(d.date))
  const sessions = series.map((d) => toNum(d.sessionCount))
  const questions = series.map((d) => toNum(d.questionCount))
  return {
    ...chartBase(),
    color: ['#5ef0c8', '#ecd27b'],
    tooltip: {
      trigger: 'axis',
      formatter: (params) => {
        if (!Array.isArray(params) || !params.length) {
          return ''
        }
        const idx = params[0].dataIndex
        const row = series[idx] || {}
        const title = row.date || dates[idx] || ''
        const lines = params.map((p) => `${p.marker}${p.seriesName}: ${p.value ?? 0}`)
        return `${title}<br/>${lines.join('<br/>')}`
      }
    },
    legend: {
      top: 0,
      right: 8,
      textStyle: { color: '#a8d4c8', fontSize: 10 },
      itemWidth: 12,
      itemHeight: 8
    },
    grid: { ...GRID, top: 28, bottom: 24 },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: dates,
      axisLabel: { ...AXIS_LABEL, fontSize: 9 },
      axisLine: AXIS_LINE
    },
    yAxis: {
      type: 'value',
      minInterval: 1,
      axisLabel: AXIS_LABEL,
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    series: [
      {
        name: '会话数',
        type: 'line',
        smooth: true,
        symbol: 'circle',
        symbolSize: 4,
        areaStyle: { color: 'rgba(94, 240, 200, 0.35)' },
        data: sessions
      },
      {
        name: '提问量',
        type: 'line',
        smooth: true,
        symbol: 'circle',
        symbolSize: 4,
        areaStyle: { color: 'rgba(236, 210, 123, 0.35)' },
        data: questions
      }
    ]
  }
}

/** 疫苗接种 — 免疫率环形饼图（中心显示免疫率） */
export function buildVaccinationOverviewOption(vaccinationOverview) {
  if (!vaccinationOverview) {
    return emptyOption('暂无接种数据')
  }
  const rate = Math.max(0, Math.min(100, toNum(vaccinationOverview.immunityRate)))
  const rateText = `${rate.toFixed(rate % 1 === 0 ? 0 : 1)}%`
  const remain = Math.max(0, 100 - rate)
  return {
    ...chartBase(),
    tooltip: {
      trigger: 'item',
      formatter: (p) => {
        if (p.name === '剩余') {
          return `未达免疫率<br/>${Number(p.value).toFixed(1)}%`
        }
        return `免疫率<br/>${rateText}`
      }
    },
    series: [
      // 外圈装饰轨
      {
        type: 'pie',
        radius: ['68%', '70%'],
        center: ['50%', '52%'],
        silent: true,
        z: 1,
        label: { show: false },
        data: [
          {
            value: 1,
            itemStyle: { color: 'rgba(60, 182, 239, 0.25)' }
          }
        ]
      },
      {
        type: 'pie',
        radius: ['48%', '64%'],
        center: ['50%', '52%'],
        startAngle: 90,
        avoidLabelOverlap: false,
        label: { show: false },
        labelLine: { show: false },
        z: 2,
        data: [
          {
            name: '免疫率',
            value: rate || 0.0001,
            itemStyle: {
              color: '#3CB6EF',
              shadowBlur: 10,
              shadowColor: 'rgba(60, 182, 239, 0.45)'
            }
          },
          {
            name: '剩余',
            value: remain <= 0 ? 0.0001 : remain,
            itemStyle: { color: 'rgba(8, 40, 56, 0.85)' },
            tooltip: { show: remain > 0 }
          }
        ]
      }
    ],
    graphic: [
      {
        type: 'text',
        left: 'center',
        top: '42%',
        style: {
          text: rateText,
          fill: '#ecd27b',
          fontSize: 22,
          fontWeight: 700,
          textAlign: 'center'
        }
      },
      {
        type: 'text',
        left: 'center',
        top: '58%',
        style: {
          text: '免疫率',
          fill: '#a8d4c8',
          fontSize: 12,
          textAlign: 'center'
        }
      }
    ]
  }
}

/** 线下预约服务 — 月度三类预约次数柱图 */
export function buildAppointmentBarOption(appointment) {
  const series = appointment?.monthlyStacked || []
  if (!series.length) {
    return emptyOption('暂无预约数据')
  }
  const months = series.map((row) => `${row.month}月`)
  const vet = series.map((row) => toNum(row.vetCount))
  const expert = series.map((row) => toNum(row.expertCount))
  const org = series.map((row) => toNum(row.orgCount))
  if (!vet.some((v) => v > 0) && !expert.some((v) => v > 0) && !org.some((v) => v > 0)) {
    return emptyOption('暂无预约数据')
  }
  return {
    ...chartBase(),
    color: ['#5ef0c8', '#ecd27b', '#3CB6EF'],
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params) => {
        if (!Array.isArray(params) || !params.length) {
          return ''
        }
        const idx = params[0].dataIndex
        const row = series[idx] || {}
        const title =
          row.statYear != null && row.month != null
            ? `${row.statYear}年${row.month}月`
            : params[0].axisValueLabel || ''
        const lines = params.map((p) => `${p.marker}${p.seriesName}: ${p.value ?? 0} 次`)
        return `${title}<br/>${lines.join('<br/>')}`
      }
    },
    legend: {
      top: 0,
      right: 0,
      itemWidth: 8,
      itemHeight: 8,
      itemGap: 6,
      textStyle: { color: '#a8d4c8', fontSize: 9 }
    },
    grid: { left: 4, right: 4, top: 24, bottom: 2, containLabel: true },
    xAxis: {
      type: 'category',
      data: months,
      axisLabel: { ...AXIS_LABEL, fontSize: 9, interval: 0 },
      axisLine: AXIS_LINE
    },
    yAxis: {
      type: 'value',
      minInterval: 1,
      axisLabel: { ...AXIS_LABEL, fontSize: 9 },
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    series: [
      {
        name: '兽医',
        type: 'bar',
        barMaxWidth: 10,
        barGap: '20%',
        itemStyle: { borderRadius: [2, 2, 0, 0], color: '#5ef0c8' },
        data: vet
      },
      {
        name: '专家',
        type: 'bar',
        barMaxWidth: 10,
        itemStyle: { borderRadius: [2, 2, 0, 0], color: '#ecd27b' },
        data: expert
      },
      {
        name: '诊疗机构',
        type: 'bar',
        barMaxWidth: 10,
        itemStyle: { borderRadius: [2, 2, 0, 0], color: '#3CB6EF' },
        data: org
      }
    ]
  }
}

/** 畜牧产品产量 — 所选年 1～N 月肉/奶对比柱图（万吨） */
export function buildProductOutputTrendOption(productOutputTrend) {
  const series = productOutputTrend?.monthlySeries || []
  if (!series.length) {
    return emptyOption('暂无产量数据')
  }
  const months = series.map((row) => `${row.month}月`)
  const meat = series.map((row) => toNum(row.meatOutput))
  const milk = series.map((row) => toNum(row.milkOutput))
  if (!meat.some((v) => v > 0) && !milk.some((v) => v > 0)) {
    return emptyOption('暂无产量数据')
  }
  return {
    ...chartBase(),
    color: ['#6CF0C8', '#3CB6EF'],
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params) => {
        if (!Array.isArray(params) || !params.length) {
          return ''
        }
        const title = params[0].axisValueLabel || params[0].name || ''
        const lines = params.map(
          (p) => `${p.marker}${p.seriesName}: ${Number(p.value ?? 0).toFixed(4)} 万吨`
        )
        return `${title}<br/>${lines.join('<br/>')}`
      }
    },
    legend: {
      top: 0,
      right: 4,
      textStyle: { color: '#a8d4c8', fontSize: 10 },
      itemWidth: 10,
      itemHeight: 8
    },
    grid: { left: 8, right: 8, top: 28, bottom: 4, containLabel: true },
    xAxis: {
      type: 'category',
      data: months,
      axisLabel: { ...AXIS_LABEL, fontSize: 9, interval: 0 },
      axisLine: AXIS_LINE
    },
    yAxis: {
      type: 'value',
      name: '万吨',
      nameTextStyle: { color: '#7aa89a', fontSize: 9, padding: [0, 0, 0, 8] },
      axisLabel: { ...AXIS_LABEL, fontSize: 9 },
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    series: [
      {
        name: '肉产量',
        type: 'bar',
        barMaxWidth: 14,
        barGap: '30%',
        itemStyle: {
          borderRadius: [3, 3, 0, 0],
          color: '#6CF0C8'
        },
        data: meat
      },
      {
        name: '奶产量',
        type: 'bar',
        barMaxWidth: 14,
        itemStyle: {
          borderRadius: [3, 3, 0, 0],
          color: '#3CB6EF'
        },
        data: milk
      }
    ]
  }
}

/** 三资具体问题上报 — 横向柱状排行（按次数降序） */
export function buildProblemReportShareOption(problemReportShare) {
  const items = [...(problemReportShare?.items || [])]
  if (!items.length) {
    return emptyOption('暂无上报数据')
  }
  const sorted = items.sort((a, b) => toNum(b.count) - toNum(a.count))
  const hasData = sorted.some((item) => toNum(item.count) > 0)
  if (!hasData) {
    return emptyOption('暂无上报数据')
  }
  // 横向柱图：类目自上而下按排行展示
  const names = sorted.map((item) => item.levelName || item.levelCode || '未知')
  const values = sorted.map((item) => toNum(item.count))
  const levelColor = {
    general: '#5ef0c8',
    key: '#ecd27b',
    major: '#ff7b7b'
  }
  return {
    ...chartBase(),
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params) => {
        const p = Array.isArray(params) ? params[0] : params
        if (!p) {
          return ''
        }
        const row = sorted[p.dataIndex] || {}
        const ratio = row.ratio != null ? `${Number(row.ratio).toFixed(1)}%` : '—'
        return `${p.name}<br/>上报 ${p.value ?? 0} 次<br/>占比 ${ratio}`
      }
    },
    grid: { left: 8, right: 48, top: 8, bottom: 8, containLabel: true },
    xAxis: {
      type: 'value',
      minInterval: 1,
      axisLabel: { ...AXIS_LABEL, fontSize: 9 },
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    yAxis: {
      type: 'category',
      inverse: true,
      data: names,
      axisLabel: { ...AXIS_LABEL, fontSize: 11, color: '#c8e8dc' },
      axisLine: { show: false },
      axisTick: { show: false }
    },
    series: [
      {
        type: 'bar',
        barMaxWidth: 16,
        barCategoryGap: '42%',
        label: {
          show: true,
          position: 'right',
          color: '#a8d4c8',
          fontSize: 10,
          formatter: (p) => {
            const row = sorted[p.dataIndex] || {}
            const ratio = row.ratio != null ? `${Number(row.ratio).toFixed(0)}%` : ''
            return ratio ? `${p.value} · ${ratio}` : `${p.value}`
          }
        },
        itemStyle: {
          borderRadius: [0, 4, 4, 0],
          color: (params) => {
            const code = sorted[params.dataIndex]?.levelCode
            return levelColor[code] || BAR_COLORS[params.dataIndex % BAR_COLORS.length]
          }
        },
        data: values
      }
    ]
  }
}

/** 用户结构 — 新老用户对比柱图 */
export function buildUserStructureOption(userStructure) {
  if (!userStructure) {
    return emptyOption('暂无用户数据')
  }
  const newCount = toNum(userStructure.newUserCount)
  const oldCount = toNum(userStructure.oldUserCount)
  // if (newCount === 0 && oldCount === 0) {
  //   return emptyOption('暂无用户数据')
  // }
  const newRatio = userStructure?.newUserRatio != null ? Number(userStructure.newUserRatio).toFixed(1) : null
  const oldRatio = userStructure?.oldUserRatio != null ? Number(userStructure.oldUserRatio).toFixed(1) : null
  return {
    ...chartBase(),
    color: ['#5ef0c8', '#ecd27b'],
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params) => {
        const p = params[0]
        const ratio = p.dataIndex === 0 ? newRatio : oldRatio
        const ratioText = ratio != null ? ` (${ratio}%)` : ''
        return `${p.name}<br/>${p.value} 人${ratioText}`
      }
    },
    grid: { ...GRID, top: 16, bottom: 24 },
    xAxis: {
      type: 'category',
      data: ['新用户', '老用户'],
      axisLabel: { ...AXIS_LABEL, fontSize: 10 },
      axisLine: AXIS_LINE
    },
    yAxis: {
      type: 'value',
      minInterval: 1,
      axisLabel: AXIS_LABEL,
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    series: [
      {
        type: 'bar',
        barMaxWidth: 48,
        itemStyle: {
          borderRadius: [4, 4, 0, 0],
          color: (params) => BAR_COLORS[params.dataIndex % BAR_COLORS.length]
        },
        data: [newCount, oldCount]
      }
    ]
  }
}

/** 提问分类占比 — 2D 环形饼图（对齐交易销售店铺入驻样式） */
export function buildCategoryShareOption(categoryShare) {
  const items = categoryShare?.items || []
  const data = items
    .filter((item) => (item.count ?? 0) > 0)
    .map((item) => ({
      name: item.categoryName || item.categoryCode || '未分类',
      value: item.count ?? 0
    }))
  if (!data.length) {
    return emptyOption('暂无分类数据')
  }
  const total =
    categoryShare?.totalAskerMessages ?? data.reduce((sum, item) => sum + item.value, 0)
  if (!(total > 0)) {
    return emptyOption('暂无分类数据')
  }
  return buildMallPie2DOption(data, {
    summaryTitle: String(total),
    summarySubtext: '提问量(条)',
    legend: {
      formatter: (name) => (name.length > 6 ? `${name.slice(0, 5)}…` : name),
      itemGap: 4
    },
    tooltipFormatter: (p) => {
      const row = items.find((it) => (it.categoryName || it.categoryCode || '未分类') === p.name)
      const ratio = row?.ratio != null ? `${Number(row.ratio).toFixed(1)}%` : `${p.percent}%`
      return `${p.name}<br/>${p.value} 条 (${ratio})`
    }
  })
}

/** 模型调用分析 — 分类条数柱图 */
export function buildModelCallOption(modelCallAnalysis) {
  const list = modelCallAnalysis || []
  if (!list.length) {
    return emptyOption('暂无调用数据')
  }
  const names = list.map((r) => r.categoryName || r.categoryCode || '')
  const values = list.map((r) => toNum(r.count))
  return {
    ...chartBase(),
    color: BAR_COLORS,
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' }
    },
    grid: { ...GRID, top: 12, bottom: 28 },
    xAxis: {
      type: 'category',
      data: names,
      axisLabel: {
        ...AXIS_LABEL,
        interval: 0,
        fontSize: 9,
        rotate: names.some((n) => n.length > 4) ? 20 : 0
      },
      axisLine: AXIS_LINE
    },
    yAxis: {
      type: 'value',
      minInterval: 1,
      axisLabel: AXIS_LABEL,
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    series: [
      {
        type: 'bar',
        barMaxWidth: 28,
        itemStyle: {
          borderRadius: [4, 4, 0, 0],
          color: (params) => BAR_COLORS[params.dataIndex % BAR_COLORS.length]
        },
        data: values
      }
    ]
  }
}

/** 分时使用热度 — 最近 24 整点小时（会话柱 + 提问量折线） */
export function buildHourlyHeatOption(hourlyHeat) {
  const series = hourlyHeat?.hourlySeries || []
  if (!series.length) {
    return emptyOption('暂无热度数据')
  }
  const labels = series.map((d) => d.bucketStart || d.bucket_start || '')
  const sessions = series.map((d) => toNum(d.sessionCount ?? d.session_count))
  const questions = series.map((d) => toNum(d.questionCount ?? d.question_count))
  return {
    ...chartBase(),
    color: ['#5ef0c8', '#ecd27b'],
    tooltip: {
      trigger: 'axis',
      formatter: (params) => {
        if (!Array.isArray(params) || !params.length) {
          return ''
        }
        const idx = params[0].dataIndex
        const row = series[idx] || {}
        const title = row.bucketDateTime || row.bucket_date_time || row.bucketStart || ''
        const lines = params.map((p) => `${p.marker}${p.seriesName}: ${p.value ?? 0}`)
        return `${title}<br/>${lines.join('<br/>')}`
      }
    },
    legend: {
      top: 0,
      right: 8,
      textStyle: { color: '#a8d4c8', fontSize: 10 },
      itemWidth: 12,
      itemHeight: 8
    },
    grid: { ...GRID, top: 28, bottom: 24, left: 36, right: 36 },
    xAxis: {
      type: 'category',
      data: labels,
      axisLabel: {
        ...AXIS_LABEL,
        fontSize: 8,
        interval: (idx) => idx % 3 === 0
      },
      axisLine: AXIS_LINE
    },
    yAxis: [
      {
        type: 'value',
        minInterval: 1,
        axisLabel: { ...AXIS_LABEL, fontSize: 9 },
        axisLine: AXIS_LINE,
        splitLine: SPLIT_LINE
      },
      {
        type: 'value',
        minInterval: 1,
        axisLabel: { ...AXIS_LABEL, fontSize: 9 },
        axisLine: AXIS_LINE,
        splitLine: { show: false }
      }
    ],
    series: [
      {
        name: '会话数',
        type: 'bar',
        barMaxWidth: 8,
        itemStyle: { color: 'rgba(94, 240, 200, 0.75)', borderRadius: [2, 2, 0, 0] },
        data: sessions
      },
      {
        name: '提问量',
        type: 'line',
        yAxisIndex: 1,
        smooth: true,
        symbol: 'none',
        lineStyle: { width: 2, color: '#ecd27b' },
        data: questions
      }
    ]
  }
}

/** 单次会话提问数量分布 — 环形图 */
export function buildSessionReplyOption(sessionReplyDistribution) {
  const list = sessionReplyDistribution || []
  if (!list.length) {
    return emptyOption('暂无分布数据')
  }
  const data = list
    .map((item, i) => ({
      name: item.bandName || item.bandCode,
      value: toNum(item.sessionCount),
      itemStyle: { color: PIE_COLORS[i % PIE_COLORS.length] }
    }))
  if (!data.length) {
    return emptyOption('暂无分布数据')
  }
  return {
    ...chartBase(),
    tooltip: {
      trigger: 'item',
      formatter: (p) => {
        const row = list.find((it) => (it.bandName || it.bandCode) === p.name)
        const ratio = row?.ratio != null ? `${Number(row.ratio).toFixed(1)}%` : `${p.percent}%`
        return `${p.name}<br/>${p.value} 会话 (${ratio})`
      }
    },
    series: [
      {
        type: 'pie',
        radius: ['42%', '68%'],
        center: ['50%', '54%'],
        label: {
          color: '#e8eef5',
          fontSize: 9,
          formatter: (p) => {
            const row = list.find((it) => (it.bandName || it.bandCode) === p.name)
            const ratio = row?.ratio != null ? Number(row.ratio).toFixed(1) : p.percent
            return `${p.name}\n${ratio}%`
          }
        },
        labelLine: { length: 6, length2: 4 },
        data
      }
    ]
  }
}

/** 会话状态分布 — 柱图（正常应答 / 调用失败） */
export function buildReplyStatusOption(replyStatusDistribution) {
  const items = replyStatusDistribution?.items || []
  if (!items.length) {
    return emptyOption('暂无状态数据')
  }
  const names = items.map((r) => r.statusName || r.statusCode || '')
  const values = items.map((r) => toNum(r.count))
  return {
    ...chartBase(),
    color: ['#5ef0c8', '#f56c6c'],
    tooltip: {
      trigger: 'axis',
      axisPointer: { type: 'shadow' },
      formatter: (params) => {
        const p = params[0]
        const row = items[p.dataIndex]
        const ratio = row?.ratio != null ? `${Number(row.ratio).toFixed(1)}%` : ''
        return `${p.name}<br/>${p.value} 条${ratio ? ` (${ratio})` : ''}`
      }
    },
    grid: { ...GRID, top: 12, bottom: 28 },
    xAxis: {
      type: 'category',
      data: names,
      axisLabel: { ...AXIS_LABEL, interval: 0, fontSize: 9 },
      axisLine: AXIS_LINE
    },
    yAxis: {
      type: 'value',
      minInterval: 1,
      axisLabel: AXIS_LABEL,
      axisLine: AXIS_LINE,
      splitLine: SPLIT_LINE
    },
    series: [
      {
        type: 'bar',
        barMaxWidth: 36,
        itemStyle: {
          borderRadius: [4, 4, 0, 0],
          color: (params) => (params.dataIndex === 0 ? '#5ef0c8' : '#f56c6c')
        },
        data: values
      }
    ]
  }
}

/** 高频关键词 — ECharts 词云 */
export function buildWordCloudOption(topKeywords) {
  const list = topKeywords || []
  if (!list.length) {
    return emptyOption('暂无关键词')
  }
  const data = list
    .filter((item) => item.keyword)
    .map((item) => ({
      name: item.keyword,
      value: toNum(item.count)
    }))
  if (!data.length) {
    return emptyOption('暂无关键词')
  }
  return {
    ...chartBase(),
    tooltip: {
      show: true,
      formatter: (p) => `${p.name}: ${p.value}`
    },
    series: [
      {
        type: 'wordCloud',
        shape: 'circle',
        left: 'center',
        top: 'center',
        width: '96%',
        height: '96%',
        sizeRange: [10, 26],
        rotationRange: [-15, 15],
        rotationStep: 15,
        gridSize: 7,
        drawOutOfBound: false,
        textStyle: {
          fontFamily: 'Microsoft YaHei, sans-serif',
          fontWeight: 'bold',
          color: () => WORD_COLORS[Math.floor(Math.random() * WORD_COLORS.length)]
        },
        emphasis: {
          textStyle: {
            shadowBlur: 8,
            shadowColor: 'rgba(94, 240, 200, 0.6)'
          }
        },
        data
      }
    ]
  }
}

/** 实战培训报名 — 双折线面积图（活动数 / 报名人数；横轴仅月，悬停显年月） */
export function buildTrainingTrendOption(trainingTrend) {
  if (!trainingTrend?.hasTrainingData) {
    return emptyOption('暂无培训数据')
  }
  const monthly = [...(trainingTrend.monthly || [])].sort(
    (a, b) => toNum(a.month) - toNum(b.month)
  )
  if (!monthly.length) {
    return emptyOption('暂无培训数据')
  }
  const categories = monthly.map((row) => `${toNum(row.month)}月`)
  const activity = monthly.map((row) => toNum(row.activityCount ?? row.activity_count))
  const enrolled = monthly.map((row) => toNum(row.enrolledCount ?? row.enrolled_count))
  const tooltipTitle = (idx) => {
    const row = monthly[idx]
    if (!row) {
      return ''
    }
    const year = row.statYear != null ? row.statYear : ''
    return year !== '' ? `${year}年${toNum(row.month)}月` : `${toNum(row.month)}月`
  }

  return {
    ...chartBase(),
    color: ['#ff9f43', '#40e0d0'],
    tooltip: {
      trigger: 'axis',
      formatter: (params) => {
        if (!Array.isArray(params) || !params.length) {
          return ''
        }
        const title = tooltipTitle(params[0].dataIndex)
        const lines = params.map((p) => {
          const unit = p.seriesName === '活动数' ? '个' : '人'
          return `${p.marker}${p.seriesName} ${p.value ?? 0} ${unit}`
        })
        return `${title}<br/>${lines.join('<br/>')}`
      }
    },
    legend: {
      top: 0,
      right: 'center',
      itemWidth: 10,
      itemHeight: 8,
      textStyle: { color: '#a8d4c8', fontSize: 10 }
    },
    grid: { left: 8, right: 8, top: 28, bottom: 4, containLabel: true },
    xAxis: {
      type: 'category',
      data: categories,
      boundaryGap: false,
      axisLabel: { ...AXIS_LABEL, fontSize: 9, interval: 0 },
      axisLine: AXIS_LINE,
      axisTick: { show: false }
    },
    yAxis: [
      {
        type: 'value',
        name: '个',
        nameTextStyle: { color: '#7aa89a', fontSize: 9, padding: [0, 0, 0, 8] },
        minInterval: 1,
        axisLabel: { ...AXIS_LABEL, fontSize: 9 },
        axisLine: AXIS_LINE,
        axisTick: { show: false },
        splitLine: SPLIT_LINE
      },
      {
        type: 'value',
        name: '人',
        nameTextStyle: { color: '#7aa89a', fontSize: 9, padding: [0, 8, 0, 0] },
        minInterval: 1,
        axisLabel: { ...AXIS_LABEL, fontSize: 9 },
        axisLine: AXIS_LINE,
        axisTick: { show: false },
        splitLine: { show: false }
      }
    ],
    series: [
      {
        name: '活动数',
        type: 'line',
        smooth: true,
        symbol: 'none',
        yAxisIndex: 0,
        lineStyle: {
          color: '#ff9f43',
          width: 2,
          shadowColor: 'rgba(255, 159, 67, 0.65)',
          shadowBlur: 10
        },
        areaStyle: {
          color: {
            type: 'linear',
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              { offset: 0, color: 'rgba(255, 159, 67, 0.55)' },
              { offset: 1, color: 'rgba(255, 159, 67, 0.04)' }
            ]
          }
        },
        data: activity
      },
      {
        name: '报名人数',
        type: 'line',
        smooth: true,
        symbol: 'none',
        yAxisIndex: 1,
        lineStyle: {
          color: '#40e0d0',
          width: 2,
          shadowColor: 'rgba(64, 224, 208, 0.65)',
          shadowBlur: 10
        },
        areaStyle: {
          color: {
            type: 'linear',
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              { offset: 0, color: 'rgba(64, 224, 208, 0.5)' },
              { offset: 1, color: 'rgba(64, 224, 208, 0.04)' }
            ]
          }
        },
        data: enrolled
      }
    ]
  }
}
