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

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

// ====================== 类型定义 ======================
type DataArr = (string | number)[];

// ====================== Props ======================
interface Props {
  datax?: DataArr;
  datay?: DataArr;
  answerScore?: DataArr;
  color?: string;
  height?: number;
  unit?: string;
  showNuitY?: boolean;
  showSplitArea?: boolean;
  showTooltip?: boolean;
  tooltipData?: Array<{ list: Array<{ name: string; value: string | number }> }>;
  typeName?: string;
  average?: string | number;
  isShowMarkLine?: boolean;
  showMarkPoint?: boolean;
  isClick?: boolean;
  answerValue?: string;
  unitX?: string;
  fullMark?: string | number;
}

const props = withDefaults(defineProps<Props>(), {
  datax: () => [],
  datay: () => [],
  answerScore: () => [],
  color: "#5470C6",
  height: 380,
  unit: "%",
  showNuitY: true,
  showSplitArea: false,
  showTooltip: true,
  tooltipData: () => [],
  typeName: "",
  average: "0",
  isShowMarkLine: true,
  showMarkPoint: false,
  isClick: false,
  answerValue: "",
  unitX: "",
  fullMark: "",
});

// ====================== Emits ======================
interface Emits {
  (e: "HandleChartClick", index: number, xName: string): void;
}
const emit = defineEmits<Emits>();

// ====================== 响应式状态 ======================
const barEchartRef = ref<HTMLDivElement | null>(null);
let echartInstance: ECharts | null = null;
const currentIndex = ref<number>(0);

// ====================== 工具方法 ======================
/** 销毁图表实例 */
function disposeEchart() {
  if (echartInstance) {
    echartInstance.dispose();
    echartInstance = null;
  }
}

/** 窗口自适应节流函数 */
const handleResize = throttle(async () => {
  await nextTick();
  LoadEchart();
}, 500);

/** 加载渲染图表 */
async function LoadEchart() {
  if (!barEchartRef.value) return;
  disposeEchart();

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

  const datax = props.datax;
  const datay = props.datay;
  const answerScore = props.answerScore;
  const rightAnswerValue = props.answerValue || "";
  const fullMark = props.fullMark;
  const typeName = props.typeName || "";
  const unit = props.unit;
  const yAxisUnit = props.showNuitY ? unit : "";
  const totalWidth = barEchartRef.value.clientWidth;

  // 颜色数组
  const colors: string[] = [];
  for (let i = 0; i < datax.length; i++) {
    if (props.color) {
      colors.push(props.color);
    } else {
      const colorArr = getScorePerformanceAnalysis();
      colors.push(colorArr[i] ?? "#5470C6");
    }
  }

  // 计算Y轴极值
  const numDatay = datay.map((v) => Number(v));
  const maxValue = Math.max(...numDatay);
  const minValue = Math.min(...numDatay);
  const average = Number(props.average) || 0;
  const nearestValue = Math.ceil((maxValue + maxValue * 0.2) / 10) * 10;

  // dataZoom 计算
  const barMinWidth = 30;
  const dataZoomNum = Math.floor((totalWidth - 47) / barMinWidth);
  const dataZoomEnd = datax.length ? Math.floor((100 / datax.length) * dataZoomNum) : 0;
  let isShowDataZoom = ((totalWidth - 97) / datax.length) < barMinWidth;
  let singleSeriesWidth = ((totalWidth - 97) / datax.length).toFixed(2);
  if (isShowDataZoom) singleSeriesWidth = String(barMinWidth);

  const dataZoom = {
    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 splitArea = props.showSplitArea
    ? { show: true, areaStyle: { color: ["#fafafa", "#ffffff"] } }
    : {};

  // 构造系列数据
  const seriesData = datay.map((value) => {
    const numVal = Number(value);
    return {
      value: numVal,
      label: {
        show: props.showMarkPoint ? (numVal === 0 || numVal === maxValue || numVal === minValue) : true,
        position: "top" as const,
        fontSize: 14,
        formatter: `{c}${unit}`,
        color: "#666",
      },
    };
  });

  // markPoint 数据
  const markPointData = datay
    .map((value, index) => {
      const valNum = Number(value);
      if (valNum === maxValue || valNum === minValue) {
        return {
          name: valNum === maxValue ? "最大值" : "最小值",
          coord: [datax[index], valNum],
          symbolSize: 65,
          label: {
            show: true,
            position: "inside" as const,
            color: "#fff",
            formatter: `${valNum}${unit}`,
          },
          itemStyle: { color: props.color },
        };
      }
      return null;
    })
    .filter((item): item is NonNullable<typeof item> => item !== null);

  const series: BarSeriesOption[] = [
    {
      name: "阅卷进度",
      type: "bar",
      barMaxWidth: 50,
      barMinWidth: 20,
      itemStyle: {
        color: (params) => {
          if (String(params.name) === rightAnswerValue || String(params.name) === String(fullMark)) {
            return "#3BA272";
          }
          return colors[params.dataIndex] ?? "#5470C6";
        },
      },
      data: seriesData,
      markLine: {
        symbol: average === 0 ? ["none", "none"] : ["circle", "arrow"],
        symbolSize: [8, 8],
        symbolOffset: [[0, 0], [0, 0]],
        label: {
          color: "#F56C6C",
          fontSize: 15,
          formatter: `{c}${unit}`,
          position: "end",
        },
        data: average !== 0 ? [{ type: "value", name: "", yAxis: average }] : [],
        lineStyle: { color: "#F56C6C" },
      },
      markPoint: props.showMarkPoint
        ? {
            data: markPointData,
            label: { show: true, fontSize: 10, fontWeight: "bold" },
          }
        : undefined,
    },
  ];

  const option: 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-wrap:break-word;max-width: 400px;",
      borderColor: "#fff",
      formatter: (params: any[]) => {
        const p = params[0] ?? params;
        let tooltip = `<div class='tooltip_content'>`;
        const title = p?.name ?? "";
        const value = p?.value ?? "";
        tooltip += `<div class='tooltip_title'>${title}</div>`;
        tooltip += `<div class='tooltip_student'>${typeName}：${value}${unit}</div>`;
        if (props.tooltipData.length > 0 && p.dataIndex != null) {
          const list = props.tooltipData[p.dataIndex]?.list ?? [];
          list.forEach((item) => {
            tooltip += `<div class='tooltip_student'>${item.name}：${item.value}</div>`;
          });
        }
        tooltip += `</div>`;
        return tooltip;
      },
    },
    grid: {
      left: 20,
      right: 27,
      top: 20,
      bottom: 0,
      containLabel: true,
    },
    dataZoom: isShowDataZoom ? [dataZoom] : undefined,
    xAxis: [
      {
        type: "category",
        data: datax,
        axisPointer: { type: "shadow" },
        axisLabel: {
          interval: 0,
          rotate: Number(singleSeriesWidth) < 60 ? 45 : 0,
          color: "#666666",
          width: 80,
          overflow: "truncate",
          ellipsis: "...",
          fontSize: 14,
          formatter: (value: string) => {
            const w = value.length * 16;
            const sw = Number(singleSeriesWidth);
            if (w > sw) {
              if (sw < 60) return value;
              const maxLen = Math.floor(sw / 16);
              return value.slice(0, maxLen) + "...";
            }
            return value;
          },
        },
      },
    ],
    yAxis: {
      type: "value",
      axisLabel: {
        color: "#666666",
        fontSize: 14,
        formatter: `{value}${yAxisUnit}`,
      },
      splitArea,
    },
    series,
  };

  echartInstance.setOption(option);

  // 点击事件
  if (props.isClick) {
    const gridRect = echartInstance.getModel().getComponent("grid").coordinateSystem.getRect();
    const xAxisDataLength = datax.length;
    let calcSingleLabelWidth = xAxisDataLength ? gridRect.width / xAxisDataLength : 0;
    if (isShowDataZoom) calcSingleLabelWidth = barMinWidth;

    echartInstance.off("click");
    echartInstance.on("click", (params: any) => {
      if (params.seriesType === "bar") {
        const idx = params.dataIndex;
        currentIndex.value = idx;
        const xName = String(params.name);
        const pixelPosition = echartInstance!.convertToPixel({ xAxisIndex: 0 }, xName);
        echartInstance!.setOption({
          graphic: {
            id: "highlight-box",
            type: "rect",
            shape: {
              x: pixelPosition - calcSingleLabelWidth / 2,
              y: gridRect.y,
              width: calcSingleLabelWidth,
              height: gridRect.height,
            },
            style: { fill: params.color + "30" },
          },
        });
        emit("HandleChartClick", idx, xName);
      }
    });

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

  // dataZoom 事件
  echartInstance.off("datazoom");
  echartInstance.on("datazoom", () => {
    const gridRect = echartInstance!.getModel().getComponent("grid").coordinateSystem.getRect();
    let calcSingleLabelWidth = props.datax.length ? gridRect.width / props.datax.length : 0;
    if (isShowDataZoom) calcSingleLabelWidth = Number(singleSeriesWidth);

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

  window.addEventListener("resize", handleResize);
}

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

onMounted(() => LoadEchart());

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
  disposeEchart();
});
</script>

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