<template>
  <div class="echart_content">
    <div class="is_show_all" v-if="showCheckBox">
      <el-checkbox
        v-model="isShowAll"
        :indeterminate="isIndeterminate"
        @change="toggleChangeAll"
      >
        显示全部
      </el-checkbox>
    </div>
    <!-- 竖向堆叠条形图 -->
    <div ref="barStackChartRef" class="chart_box"></div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onCreated, onUnmounted, nextTick, withDefaults } from 'vue'
import _throttle from 'lodash/throttle'
import * as echarts from 'echarts'
import { getScorePerformanceAnalysis } from '@/utils/common'

// ===================== 类型定义 =====================
/** 提示框额外数据项 */
interface TooltipExtraItem {
  label: string
  value: string | number
}

/** 单条提示数据 */
interface TooltipItem {
  list: TooltipExtraItem[]
  rateNum: string | number
}

/** Props 类型 */
interface BarStackChartProps {
  showCheckBox: boolean
  data: (string | number)[][]
  color: string[]
  isClick: boolean
  legendList: string[]
  tooltipData: TooltipItem[][]
}

// ===================== 常量配置 =====================
const CHART_DPR = 2
const GRID_LEFT = 40
const GRID_RIGHT = 60
const GRID_HORIZONTAL_SUM = GRID_LEFT + GRID_RIGHT
const BAR_MIN_WIDTH = 30
const BAR_MAX_WIDTH = 50
const DATA_ZOOM_HEIGHT = 8
const THROTTLE_DELAY = 500
const HIGHLIGHT_OPACITY = '30'
const DEFAULT_CHART_HEIGHT = 400

// ===================== Props 修复：纯TS类型 + withDefaults 设置默认值 =====================
const props = withDefaults(defineProps<BarStackChartProps>(), {
  showCheckBox: true,
  data: () => [],
  color: () => [],
  isClick: false,
  legendList: () => [],
  tooltipData: () => []
})

// ===================== 事件 =====================
const emit = defineEmits<{
  HandleChartClick: [index: number, name: string]
}>()

// ===================== 响应式变量 =====================
const barStackChartRef = ref<HTMLDivElement | null>(null)
let myChart: echarts.ECharts | null = null

// 多选框状态
const isShowAll = ref(true)
const isIndeterminate = ref(false)
const legendSelected = ref<Record<string, boolean>>({})
const legenSelectList = ref<string[]>([])
const legenAllList = ref<string[]>([])

// 全局颜色池
const colorsPool = ref<string[]>(getScorePerformanceAnalysis())

// 窗口缩放节流
const handleResize = _throttle(async () => {
  await nextTick()
  myChart?.resize()
}, THROTTLE_DELAY)

// ===================== 工具函数 =====================
/**
 * 生成 DataZoom 滚动条配置
 */
function getDataZoom(totalWidth: number, dataCount: number): echarts.DataZoomSliderOption | null {
  const contentWidth = totalWidth - GRID_HORIZONTAL_SUM
  const singleSeriesWidth = Math.ceil(contentWidth / dataCount)

  if (singleSeriesWidth >= BAR_MIN_WIDTH) return null

  const dataZoomNum = Math.floor(contentWidth / BAR_MIN_WIDTH)
  const dataZoomEnd = Math.floor((100 / dataCount) * dataZoomNum)

  return {
    type: 'slider',
    xAxisIndex: [0],
    start: 0,
    end: dataZoomEnd,
    height: DATA_ZOOM_HEIGHT,
    left: 20,
    right: 20,
    bottom: 0,
    borderColor: 'transparent',
    borderCap: 'round',
    fillerColor: 'transparent',
    zoomLock: true,
    handleSize: '0',
    handleStyle: {
      color: '#b8b8b8',
      borderWidth: 2
    },
    backgroundColor: 'transparent',
    showDataShadow: false,
    showDetail: false,
    filterMode: 'filter'
  }
}

/**
 * X轴文字超长截断处理
 */
function formatXLabel(value: string, singleSeriesWidth: number): string {
  const charUnit = 14
  const textWidth = value.length * charUnit

  if (textWidth <= singleSeriesWidth) return value

  if (singleSeriesWidth < 100) {
    return textWidth > 80 ? `${value.slice(0, 2)}...${value.slice(-3)}` : value
  }

  const maxLen = Math.floor(singleSeriesWidth / charUnit) - 1
  return value.slice(0, maxLen) + '...'
}

/**
 * 图例选中状态更新
 */
function updateLegendStatus() {
  isShowAll.value = legenSelectList.value.length === legenAllList.value.length
  isIndeterminate.value = legenSelectList.value.length > 0 && legenSelectList.value.length < legenAllList.value.length
}

/**
 * 绑定柱子点击与高亮效果
 */
function bindBarClick(totalWidth: number, dataCount: number) {
  if (!myChart) return

  const gridModel = myChart.getModel().getComponent('grid')
  const gridRect = gridModel.coordinateSystem.getRect()
  const xAxisDataLength = dataCount - 1
  const singleLabelWidth = gridRect.width / xAxisDataLength

  // 默认高亮第一项
  const firstItem = props.data[1]?.[0] ?? ''
  const defaultPixelPos = myChart.convertToPixel({ xAxisIndex: 0 }, firstItem)
  myChart.setOption({
    graphic: {
      id: 'highlight-box',
      type: 'rect',
      shape: {
        x: defaultPixelPos - singleLabelWidth / 2,
        y: gridRect.y,
        width: singleLabelWidth,
        height: gridRect.height
      },
      style: {
        fill: 'rgba(84,112,198,0.1)'
      }
    }
  })

  // 点击事件
  myChart.on('click', (params) => {
    if (params.seriesType !== 'bar') return

    const pixelPos = myChart.convertToPixel({ xAxisIndex: 0 }, params.name)
    myChart.setOption({
      graphic: {
        id: 'highlight-box',
        type: 'rect',
        shape: {
          x: pixelPos - singleLabelWidth / 2,
          y: gridRect.y,
          width: singleLabelWidth,
          height: gridRect.height
        },
        style: {
          fill: (params.color as string) + HIGHLIGHT_OPACITY
        }
      }
    })

    emit('HandleChartClick', params.dataIndex, params.name as string)
  })
}

// ===================== 核心：初始化图表 =====================
function loadEchart() {
  const dom = barStackChartRef.value
  if (!dom) return

  // 销毁旧实例，防止多实例叠加
  if (myChart) {
    myChart.dispose()
    myChart = null
  }

  myChart = echarts.init(dom, null, { devicePixelRatio: CHART_DPR })
  const sourceData = props.data
  if (sourceData.length === 0) return

  const dataCount = sourceData.length
  const headerRow = sourceData[0]
  const allLegend = headerRow.slice(1)
  legenAllList.value = allLegend

  // 初始化图例选中状态
  legendSelected.value = allLegend.reduce((acc, dim) => {
    acc[dim as string] = false
    return acc
  }, {} as Record<string, boolean>)

  // 优先使用外部传入图例
  if (props.legendList.length > 0) {
    legenSelectList.value = [...props.legendList]
  } else {
    legenSelectList.value = [...allLegend]
  }

  // 同步选中状态
  legenSelectList.value.forEach(item => {
    legendSelected.value[item] = true
  })
  updateLegendStatus()

  // 计算柱子宽度 & 滚动条
  const totalWidth = dom.clientWidth
  const contentWidth = totalWidth - GRID_HORIZONTAL_SUM
  const singleSeriesWidth = Math.ceil(contentWidth / dataCount)
  const dataZoomOpt = getDataZoom(totalWidth, dataCount)

  // 构建 series
  const seriesList: echarts.SeriesBarOption[] = allLegend.map((dim, index) => {
    const color = props.color[index] || colorsPool.value[index]
    return {
      type: 'bar',
      stack: 'total',
      barMaxWidth: BAR_MAX_WIDTH,
      label: {
        show: singleSeriesWidth > 22,
        position: 'inside',
        color: '#fff',
        fontSize: 12,
        formatter: (params) => {
          const val = params.value?.[params.seriesIndex + 1]
          return val === 0 ? '' : `${val}%`
        }
      },
      itemStyle: {
        color
      }
    }
  })

  // ECharts 配置项
  const option: echarts.EChartsOption = {
    dataset: {
      source: sourceData
    },
    tooltip: {
      confine: true,
      enterable: true,
      extraCssText: 'border-radius: 4px;padding:5px 0 5px 5px;white-space:normal;word-wrap:break-word;max-width: 400px;',
      triggerOn: 'mousemove',
      formatter: (params) => {
        const firstParams = Array.isArray(params) ? params[0] : params
        const title = firstParams.name ?? ''
        const rateLabelList = headerRow.slice(1)
        const dataIndex = firstParams.dataIndex

        let tooltip = `<div class="tooltip_content"><div class="tooltip_title">${title}</div>`

        rateLabelList.forEach((label, i) => {
          const rate = firstParams.value?.[i + 1]
          const curTip = props.tooltipData[dataIndex]?.[i]
          const rateNum = curTip?.rateNum ?? '-'
          const tipList = curTip?.list ?? []
          const showTip = props.tooltipData.length > 0

          const rateText = rate === '-' ? '-' : `${rate}%`
          const color = props.color[i] || colorsPool.value[i]

          if (showTip) {
            tooltip += `<div class="tooltip_student">
              <span class="tooltip_rect_icon" style="background:${color}"></span>
              ${label}：${rateText}，${rateNum}人
            </div>`
            // 最后一项追加额外提示
            if (i === rateLabelList.length - 1) {
              tipList.forEach(item => {
                tooltip += `<div class="tooltip_student">
                  <span class="tooltip_rect_icon" style="background:#CCCCCC"></span>
                  ${item.label}：${item.value}
                </div>`
              })
            }
          } else {
            tooltip += `<div class="tooltip_student">
              <span class="tooltip_rect_icon" style="background:${color}"></span>
              ${label}：${rateText}
            </div>`
          }
        })

        tooltip += '</div>'
        return tooltip
      }
    },
    legend: {
      show: true,
      left: props.showCheckBox ? '110px' : '0px',
      itemGap: 20,
      itemHeight: 10,
      itemWidth: 20,
      textStyle: { fontSize: 12, color: '#333' },
      selectedMode: true,
      selected: legendSelected.value
    },
    grid: {
      top: 50,
      left: GRID_LEFT,
      right: GRID_RIGHT,
      bottom: 0,
      containLabel: true
    },
    dataZoom: dataZoomOpt,
    yAxis: {
      type: 'value',
      axisLabel: {
        formatter: '{value}%',
        fontSize: 14,
        color: '#666',
        fontWeight: 400
      },
      axisTick: {
        lineStyle: {
          color: 'red',
          type: 'dashed',
          width: 1
        }
      }
    },
    xAxis: {
      type: 'category',
      axisLabel: {
        fontSize: 14,
        color: '#666',
        fontWeight: 400,
        interval: 0,
        rotate: singleSeriesWidth < 80 ? 45 : 0,
        formatter: (val) => formatXLabel(val, singleSeriesWidth)
      }
    },
    series: seriesList
  }

  myChart.setOption(option)

  // 图例切换监听
  myChart.on('legendselectchanged', handleLegendSelectChanged)

  // 开启柱子点击事件
  if (props.isClick) {
    bindBarClick(totalWidth, dataCount)
  }
}

// ===================== 事件处理 =====================
/**
 * 图例切换事件
 */
function handleLegendSelectChanged(params: echarts.LegendSelectChangedParams) {
  const selected = params.selected
  legenSelectList.value = []

  legenAllList.value.forEach(item => {
    if (selected[item]) {
      legenSelectList.value.push(item)
    }
  })

  updateLegendStatus()
}

/**
 * 显示全部 复选框切换
 */
function toggleChangeAll(val: boolean) {
  if (val) {
    legenSelectList.value = [...legenAllList.value]
  } else {
    legenSelectList.value = []
  }
  isIndeterminate.value = false
  loadEchart()
}

// ===================== 监听 & 生命周期 =====================
// 数据源变化重绘图表
watch(
  () => props.data,
  () => {
    loadEchart()
  },
  { deep: true }
)

onMounted(() => {
  window.addEventListener('resize', handleResize)
  loadEchart()
})

onUnmounted(() => {
  // 清除监听 & 销毁实例，防止内存泄漏
  window.removeEventListener('resize', handleResize)
  if (myChart) {
    myChart.dispose()
    myChart = null
  }
})
</script>

<style lang="scss" scoped>
.echart_content {
  width: 100%;
}

.is_show_all {
  margin-bottom: 8px;
}

.chart_box {
  width: 100%;
  height: v-bind(DEFAULT_CHART_HEIGHT + 'px');
}

:deep(.tooltip_rect_icon) {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  margin-right: 6px;
}
</style>