<template>
  <div class="echart_content" style="position: relative;">
    <div class="is_show_all" v-if="showCheckBox">
      <el-checkbox
        v-model="checkAll"
        :indeterminate="isIndeterminate"
        @change="handleCheckAllChange"
      >
        显示全部
      </el-checkbox>
    </div>
    <div class="title_right" v-if="selectBarNum === 1">
      <div
        :class="['right_item', { item_active: selectValue === item.value }]"
        v-for="item in selectOptions"
        :key="item.value"
        @click="ChangeOrder(item.value)"
      >
        {{ item.label }}
      </div>
    </div>
    <div ref="barChartsRef" class="chart_width" />
  </div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import throttle from 'lodash/throttle'
import type { ECharts, EChartsOption, LegendComponentOption, BarSeriesOption } from 'echarts'
import * as echarts from 'echarts'
import { getScorePerformanceAnalysis } from '@/utils/common'

// ==================== 工具函数 ====================
/** 安全执行 Array.includes，数组为 undefined/null 直接返回 false */
function safeIncludes<T>(arr: T[] | undefined | null, val: T): boolean {
  if (!Array.isArray(arr)) return false
  return arr.includes(val)
}

// ==================== 类型定义 ====================
type DataRow = (string | number)[]
type ChartData = DataRow[]

type SelectOption = {
  value: string
  label: string
}

type TooltipItem = {
  name: string
  value: string | number
  teacherName?: string
  studentName?: Array<{ studentName: string }>
}

type FiveTooltipItem = {
  list: Array<{ label: string; value: string | number }>
  rateNum: string | number
}

// ==================== Props ====================
interface Props {
  showCheckBox?: boolean
  color?: string[]
  data: ChartData
  title?: string
  unit?: string
  isClick?: boolean
  tooltipData?: TooltipItem[][]
  fiveTooltipData?: FiveTooltipItem[][]
  showSortSelectbox?: boolean
  legendWidth?: number | string
  gridRight?: number
  yInverse?: boolean
  showBarLegendIndex?: number,
  legendList?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  showCheckBox: true,
  color: () => [],
  title: '',
  unit: '',
  isClick: false,
  tooltipData: () => [],
  fiveTooltipData: () => [],
  showSortSelectbox: false,
  legendWidth: 'auto',
  gridRight: 60,
  yInverse: false,
  showBarLegendIndex: 1,
  legendList: () => []
})

// ==================== Emits ====================
interface Emits {
  (e: 'HandleChartClick', index: number, name: string): void
  (e: 'ChangeChartOrder', val: string, legendData: string[], selectedIndex: string | number): void
}
const emit = defineEmits<Emits>()

// ==================== 响应式状态 ====================
const barChartsRef = ref<HTMLDivElement | null>(null)
let echartInstance: ECharts | null = null

const selectValue = ref<string>('1')
const selectOptions = ref<SelectOption[]>([
  { value: '1', label: '默认' },
  { value: '2', label: '升序' },
  { value: '3', label: '降序' },
])
const selectBarNum = ref<number>(0)
const checkAll = ref<boolean>(true)
const isIndeterminate = ref<boolean>(false)
const colors = ref<string[]>(getScorePerformanceAnalysis())
const legendSelected = ref<Record<string, boolean>>({})
const legenSelectList = ref<string[]>([])
const legenAllList = ref<string[]>([])
const dataZoomEnd = ref<number>(0)
const dataZoomNum = ref<number>(5)
const currentIndex = ref<number>(0)
const isShowDataZoom = ref<boolean>(false)

// ==================== 工具函数 ====================
function disposeEchart() {
  if (echartInstance) {
    echartInstance.dispose()
    echartInstance = null
  }
}

const handleResize = throttle(async () => {
  await nextTick()
  echartInstance?.resize()
}, 500)

/** 反转Y轴数据计算 */
function getReverseData() {
  const dataList = props.data.slice(1) || []
  const flatValues: number[] = []
  dataList.forEach(item => {
    const arr = item?.slice(1) ?? []
    arr.forEach(v => {
      const num = Number(v)
      if (!isNaN(num)) flatValues.push(num)
    })
  })

  if (flatValues.length === 0) return { reverseData: [] as ChartData, dataMin: 0, dataMax: 0 }
  const dataMin = Math.min(...flatValues)
  const dataMax = Math.max(...flatValues)

  const reverseData: ChartData = []
  dataList.forEach(item => {
    const row: DataRow = []
    item.forEach((val, index) => {
      if (index === 0) {
        row.push(val)
      } else {
        const valNumber = Number(isNaN(Number(val)) ? 0 : val)
        let calcVal: number
        if (valNumber > 0) {
          calcVal = dataMax - valNumber + dataMin
        } else {
          calcVal = dataMax > dataMin ? dataMin : 0
        }
        row.push(calcVal)
      }
    })
    reverseData.push(row)
  })
  reverseData.unshift([...props.data[0]])
  return { reverseData, dataMin, dataMax }
}

/** 全选/取消全选图例 */
function ToggleChangeAll(show: boolean) {
  if (!props.showCheckBox || !echartInstance) return
  const opt = echartInstance.getOption()
  const sourceArr = opt.dataset?.[0]?.source ?? []
  const legendData: string[] = (sourceArr[0]?.slice(1) ?? []).map((v) => String(v))
  legendData.forEach(name => {
    echartInstance!.dispatchAction({
      type: show ? 'legendSelect' : 'legendUnSelect',
      name,
    })
  })
  checkAll.value = show
  isIndeterminate.value = false
}

function handleCheckAllChange() {
  ToggleChangeAll(checkAll.value)
}

/** 图例切换事件 */
function handleLegendSelectChanged(params: { selected: Record<string, boolean> }) {
  if (!echartInstance) return
  const opt = echartInstance.getOption()
  const sourceArr = opt.dataset?.[0]?.source ?? []
  const legendData: string[] = (sourceArr[0]?.slice(1) ?? []).map((v) => String(v))
  const selected = params.selected
  legendSelected.value = selected

  const allSelected = legendData.every(k => selected[k])
  const noneSelected = legendData.every(k => !selected[k])
  const someSelected = !allSelected && !noneSelected

  if (noneSelected) checkAll.value = false
  if (allSelected) checkAll.value = true
  isIndeterminate.value = someSelected

  // 更新 dataZoom
  const barMinWidth = 26
  const numSeries = Object.values(selected).filter(Boolean).length
  const echartWidth = (props.data.length - 1) * barMinWidth * numSeries
  const totalWidth = barChartsRef.value?.clientWidth ?? 0
  dataZoomNum.value = Math.floor((totalWidth - 140) / (barMinWidth * numSeries))
  dataZoomEnd.value = Math.floor((100 / Math.max(1, props.data.length - 1)) * dataZoomNum.value)

  const dataZoom = {
    start: 0,
    end: dataZoomEnd.value,
    type: 'slider',
    show: true,
    borderColor: 'transparent',
    borderCap: 'round',
    xAxisIndex: [0],
    height: 8,
    left: 20,
    right: 20,
    bottom: 0,
    fillerColor: 'transparent',
    zoomLock: true,
    handleSize: '0',
    handleStyle: {
      color: '#b8b8b8',
      borderWidth: 2,
    },
    backgroundColor: 'transparent',
    showDataShadow: false,
    showDetail: false,
    filterMode: 'filter',
    pageIconColor: '#999',
    pageIconInactiveColor: '#ccc',
  }
  if (echartWidth > totalWidth) {
    echartInstance.setOption({ dataZoom })
    echartInstance.resize()
  }

  // 更新 legenSelectList 并重绘
  legenSelectList.value = legendData.filter(item => selected[item])
  selectValue.value = '1'
  const legendDataKeys = Object.keys(selected).filter(k => selected[k])
  emit('ChangeChartOrder', selectValue.value, legendDataKeys, '')
  LoadEchart()
}

/** 排序切换 */
function ChangeOrder(val: string) {
  selectValue.value = val
  const headerRow = props.data[0] ?? []
  const legendList = headerRow.slice(1).map(v => String(v))
  const legendVal = legendList.map(item => legendSelected.value[item])
  const selectedIndex = legendVal.indexOf(true)
  const legendData = Object.keys(legendSelected.value).filter(k => legendSelected.value[k])
  emit('ChangeChartOrder', val, legendData, selectedIndex)
}

/** 初始化图表 */
async function LoadEchart() {
  if (!barChartsRef.value) return
  disposeEchart()

  echartInstance = echarts.init(barChartsRef.value, null, { devicePixelRatio: 2 })

  // 初始化图例列表，兜底空数组
  const headerRow = props.data[0] ?? []
  if (props.legendList.length > 0) {
    legenSelectList.value = [...props.legendList]
  } else {
    legenSelectList.value = headerRow.slice(1).map(v => String(v))
  }
  legenAllList.value = headerRow.slice(1).map(v => String(v))

  const { reverseData, dataMin, dataMax } = getReverseData()
  const datasetSource = props.yInverse ? reverseData : props.data
  const dataset = { source: datasetSource }

  let constColorAll = getScorePerformanceAnalysis()
  if (props.color.length > 0) constColorAll = props.color

  // 初始化图例选中状态
  const tempLegendSelected: Record<string, boolean> = {}
  const dims = headerRow.slice(1).map(v => String(v))
  dims.forEach(dim => tempLegendSelected[dim] = false)
  legenSelectList.value.forEach(item => tempLegendSelected[item] = true)
  legendSelected.value = tempLegendSelected

  checkAll.value = legenSelectList.value.length === legenAllList.value.length
  isIndeterminate.value = legenSelectList.value.length > 0 && legenSelectList.value.length < legenAllList.value.length
  const numSeries = Object.values(legendSelected.value).filter(Boolean).length
  if (props.showSortSelectbox) selectBarNum.value = numSeries

  const dataxCount = Math.max(0, props.data.length - 1)
  const totalWidth = barChartsRef.value?.clientWidth ?? 0
  const barMinWidth = 26
  dataZoomNum.value = Math.floor((totalWidth - 140) / Math.max(1, barMinWidth * numSeries))
  const xAxisTotal = Math.max(1, dataset.source.length - 1)
  dataZoomEnd.value = Math.floor((100 / xAxisTotal) * dataZoomNum.value)
  const echartWidth = (dataset.source.length - 1) * barMinWidth * numSeries
  const singleSeriesWidth = Math.ceil(Math.max(0, totalWidth - 140) / Math.max(1, dataxCount))
  isShowDataZoom.value = echartWidth > totalWidth
  let realSingleSeriesWidth = singleSeriesWidth
  if (isShowDataZoom.value) realSingleSeriesWidth = 25 * legenSelectList.value.length

  const dataZoom = {
    start: 0,
    end: dataZoomEnd.value,
    type: 'slider',
    show: true,
    borderColor: 'transparent',
    borderCap: 'round',
    xAxisIndex: [0],
    height: 8,
    left: 20,
    right: 20,
    bottom: 0,
    fillerColor: 'transparent',
    zoomLock: true,
    handleSize: '0',
    handleStyle: { color: '#b8b8b8', borderWidth: 2 },
    backgroundColor: 'transparent',
    showDataShadow: false,
    showDetail: false,
    filterMode: 'filter',
    pageIconColor: '#999',
    pageIconInactiveColor: '#ccc',
  }

  const unit = props.unit
  const series: BarSeriesOption[] = dims.map((dim, index) => {
    const seriesData = dataset.source.slice(1).map((dataRow, dataIndex) => {
      const value = dataRow[index + 1]
      const rawVal = props.yInverse ? props.data[dataIndex + 1]?.[index + 1] : value
      return {
        value,
        label: {
          show: true,
          position: Number(value) >= 0 ? 'top' : 'bottom',
          color: '#666',
          fontSize: 12,
          formatter: () => `${rawVal ?? ''}${unit}`,
        },
      }
    })
    return {
      type: 'bar',
      name: dim,
      barGap: 0,
      barCategoryGap: 30,
      barMaxWidth: 50,
      barMinWidth: 20,
      itemStyle: {
        color: constColorAll[index] ?? '#ccc',
      },
      data: seriesData,
      label: {
        show: true,
        color: '#666',
        fontSize: 12,
        formatter: (params: any) => {
          const rawVal = props.yInverse ? props.data[params.dataIndex + 1]?.[params.seriesIndex + 1] : params.value
          return `${rawVal ?? ''}${unit}`
        },
      },
    }
  })

  const option: EChartsOption = {
    dataset,
    tooltip: {
      axisPointer: { type: dataset.source.length < 3 ? 'none' : 'shadow' },
      trigger: 'axis',
      triggerOn: 'mousemove | click',
      renderMode: 'html',
      confine: true,
      extraCssText: 'border-radius: 4px;padding:5px 0px 5px 5px;white-space:normal;word-wrap:break-word;max-width: 400px;',
      enterable: true,
      formatter: (params: any[]) => {
        let tooltip = `<div class='tooltip_content'>`
        const newData = dataset.source.slice(1)
        const xAxisName = newData[params[0].dataIndex]?.[0] ?? ''
        let teachClassName = ''
        if (props.tooltipData.length > 0) {
          const tipItem = props.tooltipData[params[0].seriesIndex]?.[params[0].dataIndex]
          teachClassName = tipItem?.teacherName ?? ''
        }
        tooltip += `<div class='tooltip_title'>${xAxisName} ${teachClassName}</div>`
        params.forEach((item) => {
          const className = item.seriesName
          const rate = item.data.value !== undefined ? item.data.value : item.data[item.seriesIndex + 1]
          if (props.tooltipData.length > 0) {
            const tipItem = props.tooltipData[item.seriesIndex]?.[item.dataIndex]
            tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:${item.color}'></span>${tipItem?.name ?? ''}：${tipItem?.value ?? ''}</div>`
            const studentList = tipItem?.studentName?.map(s => s.studentName) ?? []
            const studentNames = studentList.join('、')
            if (studentNames) tooltip += `<div class='tooltip_student'><span class='tooltip_zw'></span> (${studentNames})</div>`
          } else if (props.fiveTooltipData.length > 0) {
            const tipItem = props.fiveTooltipData[item.dataIndex]?.[item.seriesIndex]
            const list = tipItem?.list ?? []
            const rateNum = tipItem?.rateNum ?? '-'
            tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:${item.color}'></span>${className}${props.title}：${rate === '-' ? '-' : rate + unit}，${rateNum}人</div>`
            if (item === params[params.length - 1]) {
              list.forEach(l => {
                tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:#CCCCCC'></span>${l.label}：${l.value}</div>`
              })
            }
          } else if (props.yInverse && props.tooltipData.length === 0) {
            const sourceData = props.data
            const dIdx = item.dataIndex + 1
            const sIdx = item.seriesIndex + 1
            const r = sourceData?.[dIdx]?.[sIdx] ?? '-'
            tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:${item.color}'></span>${className}${props.title}：${r ? r + unit : '-'}</div>`
          } else {
            tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:${item.color}'></span>${className}${props.title}：${rate ? rate + unit : '-'}</div>`
          }
        })
        tooltip += `</div>`
        return tooltip
      },
    },
    legend: {
      show: true,
      top:0,
      left: props.showCheckBox ? '110px' : 0,
      width: props.showSortSelectbox && selectBarNum.value === 1 ? '78%' : props.legendWidth,
      itemGap: 20,
      itemHeight: 10,
      itemWidth: 20,
      textStyle: { fontSize: 12, color: '#333' },
      selectedMode: true,
      selected: legendSelected.value,
      type: 'scroll',
      pageButtonItemGap: 5,
      pageButtonPosition: 'end',
      orient: 'horizontal',
      alignTo: 'none',
      pageIconColor: '#999',
      pageIconInactiveColor: '#ccc',
      formatter: (name: string) => name.replace(/g/g, 'G'),
    } as LegendComponentOption,
    dataZoom: isShowDataZoom.value ? [dataZoom] : [],
    grid: {
      top: 50,
      left: 40,
      right: props.gridRight,
      bottom: isShowDataZoom.value ? 15 : 0,
      containLabel: true,
    },
    yAxis: {
      type: 'value',
      axisLabel: {
        formatter: (val: number) => {
          let value = props.yInverse ? dataMax - val + dataMin : val
          value = props.yInverse ? Number(value.toFixed(0)) : Number(value.toFixed(1))
          return unit === '%' ? `${value}${unit}` : String(value)
        },
        textStyle: { fontSize: 14, color: '#666', fontWeight: 400 },
      },
      splitArea: {
        show: true,
        areaStyle: { color: ['#fafafa', '#ffffff'] },
      },
      min: props.yInverse ? dataMin : undefined,
      max: props.yInverse ? dataMax : undefined,
    },
    xAxis: {
      type: 'category',
      triggerEvent: true,
      axisTick: { alignWithLabel: true },
      axisLabel: {
        interval: 0,
        rotate: realSingleSeriesWidth < 80 ? 45 : 0,
        textStyle: { fontSize: 14, color: '#666', fontWeight: 400 },
        formatter: (value: number) => {
          const newData = dataset.source.slice(1)
          return String(newData[value]?.[0] ?? '')
        },
      },
    },
    series,
  }

  echartInstance.setOption(option, true)

  // 图例事件
  echartInstance.off('legendselectchanged')
  echartInstance.on('legendselectchanged', handleLegendSelectChanged)
  window.addEventListener('resize', handleResize)

  // 点击与高亮逻辑
  if (props.isClick) {
    const gridRect = echartInstance.getModel().getComponent('grid').coordinateSystem.getRect()
    const xAxisDataLength = Math.max(0, props.data.length - 1)
    let itemBarWidth = 20
    let calcSingleLabelWidth = xAxisDataLength === 0 ? 0 : gridRect.width / xAxisDataLength
    let height = 0
    if (isShowDataZoom.value) {
      calcSingleLabelWidth = numSeries * 26 - 10
    } else {
      itemBarWidth = (calcSingleLabelWidth * 0.7) / numSeries > 50 ? 50 : (calcSingleLabelWidth * 0.7) / numSeries
    }
    const updateSeries = dims.map((dim, index) => {
      const seriesData = dataset.source.slice(1).map((dataRow, dataIndex) => {
        const value = dataRow[index + 1]
        const rawVal = props.yInverse ? props.data[dataIndex + 1]?.[index + 1] : value
        return {
          value,
          label: {
            show: itemBarWidth > 23,
            position: Number(value) >= 0 ? 'top' : 'bottom',
            color: '#666',
            fontSize: 12,
            formatter: () => `${rawVal ?? ''}${unit}`,
          },
        }
      })
      return {
        type: 'bar',
        name: dim,
        barGap: 0,
        barCategoryGap: 30,
        barMaxWidth: 50,
        barMinWidth: 20,
        itemStyle: { color: constColorAll[index] },
        data: seriesData,
        label: {
          show: true,
          color: '#666',
          fontSize: 12,
          formatter: (params: any) => {
            const rawVal = props.yInverse ? props.data[params.dataIndex + 1]?.[params.seriesIndex + 1] : params.value
            return `${rawVal ?? ''}${unit}`
          },
        },
      } as BarSeriesOption
    })
    echartInstance.setOption({ series: updateSeries })

    // 点击柱子
    echartInstance.off('click')
    echartInstance.on('click', (params: any) => {
      if (params.seriesType === 'bar') {
        const dataIndex = params.dataIndex
        currentIndex.value = dataIndex
        const pixelPosition = echartInstance!.convertToPixel({ xAxisIndex: 0 }, params.name)
        echartInstance!.setOption({
          graphic: {
            id: 'highlight-box',
            type: 'rect',
            shape: {
              x: pixelPosition - calcSingleLabelWidth / 2,
              y: gridRect.y,
              width: calcSingleLabelWidth,
              height: gridRect.height - height,
            },
            style: { fill: params.color + '30' },
          },
        })
        const newData = dataset.source.slice(1)
        const name = String(newData[dataIndex]?.[0] ?? '')
        emit('HandleChartClick', dataIndex, name)
      }
    })

    // 默认高亮第一个
    if (dataset.source[1]?.length > 1) {
      const defaultPixelPosition = echartInstance.convertToPixel({ xAxisIndex: 0 }, dataset.source[1][0])
      echartInstance.setOption({
        graphic: {
          id: 'highlight-box',
          type: 'rect',
          shape: {
            x: defaultPixelPosition - calcSingleLabelWidth / 2,
            y: gridRect.y,
            width: calcSingleLabelWidth,
            height: gridRect.height - height,
          },
          style: { fill: 'rgba(84,112,198,0.1)' },
        },
      })
    }
  }

  // dataZoom 滚动事件
  echartInstance.off('datazoom')
  echartInstance.on('datazoom', (params: any) => {
    const gridRect = echartInstance!.getModel().getComponent('grid').coordinateSystem.getRect()
    let calcSingleLabelWidth = gridRect.width / Math.max(1, props.data.length)
    let height = 0
    if (isShowDataZoom.value) calcSingleLabelWidth = realSingleSeriesWidth

    const idx = currentIndex.value
    if (dataset.source.length > idx + 1) {
      const pixelPosition = echartInstance!.convertToPixel({ xAxisIndex: 0 }, dataset.source[idx + 1][0])
      echartInstance!.setOption({
        graphic: {
          id: 'highlight-box',
          type: 'rect',
          shape: {
            x: pixelPosition - calcSingleLabelWidth / 2,
            y: gridRect.y,
            width: calcSingleLabelWidth,
            height: gridRect.height - height,
          },
          style: { fill: 'rgba(84,112,198,0.1)' },
        },
      })
    }
  })
}

// ==================== 监听与生命周期 ====================
watch(
  () => props.data,
  () => {
    if (props.showSortSelectbox) {
      // 兜底空数组，防止 undefined
      const legenedList = props.data[0]?.slice(1, props.showBarLegendIndex + 1) ?? []
      const barLegendList = legenedList.filter(item => safeIncludes(props.legendList, String(item)))
      selectBarNum.value = barLegendList.length
    }
    LoadEchart()
  },
  { deep: true },
)

onMounted(() => {
  if (props.showSortSelectbox) {
    const legenedList = props.data[0]?.slice(1) ?? []
    const barLegendList = legenedList.filter(item => safeIncludes(props.legendList, String(item)))
    selectBarNum.value = barLegendList.length
    selectValue.value = '1'
  }
  LoadEchart()
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize)
  disposeEchart()
  document.querySelectorAll('#tooltipContent, #x-axis-tooltip').forEach(el => el.remove())
})
</script>

<style lang="scss" scoped>
.echart_content {
  position: relative;
  width: 100%;
  margin: auto;
  min-height: 360px;
  height: auto;
  .is_show_all {
    position: absolute;
    top: -4px;
    left: 5px;
  }
}
.chart_width {
  width: 100%;
  height: 400px;
}
.title_right {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  position: absolute;
  top: -6px;
  right: 0;
  z-index: 99;
  .right_item {
    font-size: 14px;
    color: #999;
    font-weight: 400;
    cursor: pointer;
    height: 30px;
    line-height: 32px;
    margin-right: 5px;
    border-bottom: 2px solid #ffffff;
  }
  .item_active {
    font-size: 14px;
    color: #2E64FA;
    font-weight: 500;
    cursor: pointer;
  }
}
</style>