<template>
  <div ref="barEchartRef" class="chart_width" :style="{ height: `${height}px` }"></div>
</template>

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

// ===================== 类型定义 =====================
interface TooltipItem {
  name: string
  value: string | number
}
interface TooltipDataItem {
  list: TooltipItem[]
}
interface MarkLineDataItem {
  value: string | number
  isShow: boolean
}

interface BarChartProps {
  datax: (string | number)[]
  datay: (string | number)[]
  color: string
  height?: number
  unit: string
  showNuitY?: boolean
  showSplitArea?: boolean
  showTooltip?: boolean
  tooltipData?: TooltipDataItem[]
  typeName: string
  average?: string | number | (string | number)[]
  markLineData?: MarkLineDataItem[]
  isShowMarkLine?: boolean
  showMarkPoint?: boolean
  isClick?: boolean
  answerValue?: string
  unitX?: string
  fullMark?: string | number
  gridLeft?: number
  gridRight?: number
  gridTop?: number
  fontSize?: string | number
  fontColor?: string
  showDataZoom?: boolean
  barMaxWidth?: number
  barMinWidth?: number
}

interface BarChartEmits {
  HandleChartClick: (index: number, xName: string | number) => void
  HandleBarClick: (paintingId: unknown) => void
}

// ===================== Props + 默认值（核心修复） =====================
const props = withDefaults(defineProps<BarChartProps>(), {
  datax: () => [],
  datay: () => [],
  color: '#5470C6',
  height: 380,
  unit: '%',
  showNuitY: true,
  showSplitArea: false,
  showTooltip: true,
  tooltipData: () => [],
  typeName: '',
  average: '0',
  markLineData: () => [],
  isShowMarkLine: true,
  showMarkPoint: false,
  isClick: false,
  answerValue: '',
  unitX: '',
  fullMark: '',
  gridLeft: 40,
  gridRight: 60,
  gridTop: 20,
  fontSize: '',
  fontColor: '',
  showDataZoom: true,
  barMaxWidth: 50,
  barMinWidth: 20
})

const emit = defineEmits<BarChartEmits>()

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

// ===================== 工具方法 =====================
const GetMaxValue = (value: number): number => {
  const thresholdMap = [
    { maxThreshold: 0.3, bound: 0.3 },
    { maxThreshold: 0.6, bound: 0.6 },
    { maxThreshold: 1, bound: 1 },
    { maxThreshold: 1.5, bound: 1.5 },
    { maxThreshold: 2, bound: 2 },
    { maxThreshold: 4, bound: 4 },
    { maxThreshold: 8, bound: 8 },
    { maxThreshold: 10, bound: 10 },
    { maxThreshold: 40, bound: 40 },
    { maxThreshold: 50, bound: 50 },
    { maxThreshold: 60, bound: 60 },
    { maxThreshold: 70, bound: 70 },
    { maxThreshold: 80, bound: 80 },
    { maxThreshold: 90, bound: 90 },
    { maxThreshold: 100, bound: 100 },
    { maxThreshold: 120, bound: 120 },
    { maxThreshold: 150, bound: 150 },
    { maxThreshold: 180, bound: 180 },
    { maxThreshold: 200, bound: 200 },
    { maxThreshold: 250, bound: 250 },
    { maxThreshold: 300, bound: 300 },
    { maxThreshold: 350, bound: 350 },
    { maxThreshold: 400, bound: 400 },
    { maxThreshold: 450, bound: 450 },
    { maxThreshold: 500, bound: 500 },
    { maxThreshold: 600, bound: 600 },
    { maxThreshold: 700, bound: 700 }
  ]
  const matchedRule = thresholdMap.find(item => value === item.maxThreshold || value < item.maxThreshold)
  if (matchedRule) return matchedRule.bound
  return Math.ceil(value / 10) * 10
}

const LoadEchart = () => {
  if (!barEchartRef.value) return
  if (echart) echart.dispose()

  const colors: string[] = []
  const xColors: string[] = []
  const rightAnswerValue = props.answerValue || ''
  const globalColorArr = getScorePerformanceAnalysis()

  for (let i = 0; i < props.datax.length; i++) {
    colors.push(props.color || globalColorArr[i])
    xColors.push('#666666')
  }

  const markPointColor = props.color
  echart = echarts.init(barEchartRef.value, null, { devicePixelRatio: 2 })
  const totalWidth = barEchartRef.value.clientWidth
  const singleSeriesWidth = Math.ceil((totalWidth - 140) / props.datax.length)

  const datayNumList = props.datay.filter(num => !isNaN(Number(num))).map(Number)
  const maxValue = datayNumList.length ? Math.max(...datayNumList) : 0
  const minValue = datayNumList.length ? Math.min(...datayNumList) : 0

  let average: string | number | (string | number)[] = 0
  const markLineData: echarts.MarkLineDataItem[] = []
  let maxAverage = 0

  if (Object.prototype.toString.call(props.average) === '[object Array]') {
    average = props.average
    ;(average as (string | number)[]).forEach(item => {
      const itemAvg = parseFloat(String(item)) || 0
      if (Number(item) > 0) {
        markLineData.push({ symbol: 'circle', type: 'value', name: '', yAxis: itemAvg })
      }
    })
    maxAverage = average.length ? Math.max(...(average as number[])) : 0
  } else if (props.markLineData && props.markLineData.length) {
    average = []
    props.markLineData.forEach((item, index) => {
      const itemAvg = parseFloat(String(item.value)) || 0
      ;(average as number[]).push(itemAvg)
      if (item.isShow) {
        const compareColorArr = getCompareAnalysis()
        markLineData.push({
          symbol: 'circle',
          type: 'value',
          name: '',
          yAxis: itemAvg,
          lineStyle: { color: compareColorArr[index] },
          label: { color: compareColorArr[index] }
        })
      }
    })
    maxAverage = (average as number[]).length ? Math.max(...(average as number[])) : 0
  } else {
    average = parseFloat(String(props.average)) || 0
    maxAverage = parseFloat(String(props.average)) || 0
    if (average !== 0) {
      markLineData.push({ symbol: 'circle', type: 'value', name: '', yAxis: average })
    }
  }

  const nearestValue = GetMaxValue(maxValue)
  const yAxisUnit = props.showNuitY && props.unit === '%' ? props.unit : ''
  const splitArea = props.showSplitArea
    ? { show: true, areaStyle: { color: ['#fafafa', '#ffffff'] } }
    : {}

  const barMinWidth = 30
  const dataZoomNum = Math.floor((totalWidth - 140) / (barMinWidth * 1))
  const dataZoomEnd = Math.floor((100 / props.datax.length) * dataZoomNum)

  const dataZoomOption: echarts.DataZoomSliderOption = {
    start: 0,
    end: dataZoomEnd,
    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'
  }

  const dataZoom = props.showDataZoom && singleSeriesWidth < barMinWidth ? dataZoomOption : null

  const option: echarts.EChartsOption = {
    tooltip: {
      show: props.showTooltip,
      trigger: props.showTooltip ? 'axis' : 'item',
      triggerOn: 'mousemove',
      renderMode: 'html',
      confine: true,
      extraCssText: 'border-radius: 4px;padding:5px 0px 5px 5px;white-space:normal;word-warp:break-word;max-width: 400px;',
      borderColor: '#fff',
      formatter: (params: any) => {
        let tooltip = `<div class='tooltip_content'>`
        const title = params?.name || params[0]?.name
        const value = params?.value || params[0]?.value
        tooltip += `<div class='tooltip_title'>${title}</div>`
        if (props.typeName) {
          tooltip += `<div class='tooltip_student'>${props.typeName}：${value}${props.unit}</div>`
        }
        if (props.tooltipData.length > 0) {
          const list = props.tooltipData[params[0].dataIndex]?.list || []
          for (const item of list) {
            tooltip += `<div class='tooltip_student'>${item.name}：${item.value}</div>`
          }
        }
        tooltip += `</div>`
        return tooltip
      }
    },
    grid: {
      left: props.gridLeft,
      right: props.gridRight,
      top: props.gridTop,
      bottom: 0,
      containLabel: true
    },
    dataZoom,
    xAxis: [
      {
        type: 'category',
        data: props.datax,
        axisPointer: { type: 'shadow' },
        axisLabel: {
          interval: 0,
          fontWeight: 400,
          rotate: singleSeriesWidth < 80 ? 45 : 0,
          formatter: (value: string) => {
            const valueWidth = value.length * 14
            if (valueWidth > singleSeriesWidth) {
              if (singleSeriesWidth < 100) {
                return valueWidth > 80 ? value.slice(0, 2) + '...' + value.slice(-3) : value
              } else {
                const maxLength = Math.floor(singleSeriesWidth / 14) - 1
                return value.slice(0, maxLength) + '...'
              }
            }
            return `${value}${props.unitX}`
          },
          color: props.fontColor || '#666666',
          fontSize: props.fontSize ? Number(props.fontSize) : 14
        }
      }
    ],
    yAxis: {
      type: 'value',
      axisLabel: {
        color: props.fontColor || '#666666',
        fontSize: props.fontSize ? Number(props.fontSize) : 14,
        formatter: `{value}${yAxisUnit}`
      },
      max: maxAverage > nearestValue ? maxAverage : nearestValue,
      splitArea
    },
    series: [
      {
        name: '阅卷进度',
        type: 'bar',
        barMaxWidth: props.barMaxWidth,
        barMinWidth: props.barMinWidth,
        itemStyle: {
          color: (params: any) => {
            if (params.name === rightAnswerValue || params.name === props.fullMark) return '#3BA272'
            if (params.name === '0') return '#EE6666'
            return colors[params.dataIndex]
          }
        },
        data: props.datay.map(value => ({
          value,
          label: {
            show: props.showMarkPoint ? (value === 0 || value === maxValue || value === minValue) : singleSeriesWidth > 26,
            position: 'top',
            fontSize: props.fontSize ? Number(props.fontSize) : 14,
            formatter: `{c}${props.unit}`,
            color: '#666'
          }
        })),
        markLine: props.isShowMarkLine
          ? {
              symbolSize: [8, 8],
              symbolOffset: [[0, 0], [0, 0]],
              label: {
                color: '#F56C6C',
                fontSize: props.fontSize ? Number(props.fontSize) : 15,
                formatter: `{c}${props.unit}`,
                position: 'end'
              },
              data: markLineData,
              lineStyle: props.markLineData.length ? undefined : { color: '#F56C6C' }
            }
          : undefined,
        markPoint: props.showMarkPoint
          ? {
              data: props.datay
                .map((value, index) => {
                  if (value === maxValue || value === minValue) {
                    return {
                      name: value === maxValue ? '最大值' : '最小值',
                      coord: [props.datax[index], value],
                      symbolSize: 65,
                      label: {
                        show: true,
                        position: 'inside',
                        color: '#fff',
                        formatter: `${value}${props.unit}`
                      },
                      itemStyle: { color: markPointColor }
                    }
                  }
                  return null
                })
                .filter(Boolean) as echarts.MarkPointDataItem[],
              label: { show: true, fontSize: 10, fontWeight: 'bold' }
            }
          : undefined
      }
    ]
  }

  echart.setOption(option)

  if (props.isClick) {
    const xAxisDataLength = props.datax.length
    const gridRect = echart.getModel().getComponent('grid').coordinateSystem.getRect()
    let singleLabelWidth = gridRect.width / xAxisDataLength
    if (singleSeriesWidth < barMinWidth) singleLabelWidth = barMinWidth

    echart.off('click')
    echart.on('click', (params: any) => {
      if (params.seriesType === 'bar') {
        echart?.setOption({
          series: [
            {
              itemStyle: {
                color: (p: any) => {
                  if (p.name === rightAnswerValue || p.name === props.fullMark) return '#3BA272'
                  if (p.name === '0') return '#EE6666'
                  return colors[p.dataIndex]
                }
              }
            }
          ]
        })
        const pixelPosition = echart.convertToPixel({ xAxisIndex: 0 }, params.name)
        echart?.setOption({
          graphic: {
            id: 'highlight-box',
            type: 'rect',
            shape: {
              x: pixelPosition - singleLabelWidth / 2,
              y: gridRect.y,
              width: singleLabelWidth,
              height: gridRect.height
            },
            style: { fill: `${params.color}30` }
          }
        })
        emit('HandleChartClick', params.dataIndex, params.name)
      }
    })

    const defaultPixelPosition = echart.convertToPixel({ xAxisIndex: 0 }, props.datax[0])
    echart.setOption({
      graphic: {
        id: 'highlight-box',
        type: 'rect',
        shape: {
          x: defaultPixelPosition - singleLabelWidth / 2,
          y: gridRect.y,
          width: singleLabelWidth,
          height: gridRect.height
        },
        style: { fill: 'rgba(84,112,198,0.1)' }
      }
    })
  }
}

const UpdateColors = () => {
  if (!echart) return
  const newColors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40', '#FF6384']
  echart.setOption({
    series: [
      {
        itemStyle: { color: (params: any) => newColors[params.dataIndex] }
      }
    ]
  })
}

const handleResize = _.throttle(() => {
  nextTick(() => LoadEchart())
}, 500)

// 监听 & 生命周期
watch(() => props.datay, LoadEchart, { deep: true })
watch(() => props.markLineData, LoadEchart, { deep: true })

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

onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  if (echart) {
    echart.dispose()
    echart = null
  }
})
</script>

<style lang="scss" scoped>
.chart_width {
  width: 100%;
  height: 380px;
}
</style>