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

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

// ================= Props & Emits =================
interface Props {
  showCheckBox?: boolean;
  data?: (string | number)[][];
  color?: string[];
  isClick?: boolean;
  legendList?: string[];
  tooltipData?: any[];
}

const props = withDefaults(defineProps<Props>(), {
  showCheckBox: true,
  data: () => [],
  color: () => [],
  isClick: false,
  legendList: () => [],
  tooltipData: () => [],
});

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

// ================= Refs & State =================
const barStackChart = ref<HTMLElement | null>(null);
const myChart = ref<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 defaultColors = getScorePerformanceAnalysis();

// ================= Helper Methods =================
const initLegenSelectList = () => {
  if (props.legendList.length > 0) {
    legenSelectList.value = props.legendList;
  } else {
    legenSelectList.value = (props.data[0]?.slice(1) as string[]) || [];
  }
};

// ================= Core Methods =================
const LoadEchart = () => {
  if (myChart.value) {
    myChart.value.dispose();
  }
  if (!barStackChart.value) return;

  myChart.value = echarts.init(barStackChart.value, null, {
    devicePixelRatio: 2,
  });

  if (props.data.length === 0) {
    return;
  }

  const dataset = {
    source: props.data,
  };
  const dataCount = props.data.length;

  legenAllList.value = (props.data[0]?.slice(1) as string[]) || [];

  legendSelected.value = (dataset.source[0] as string[])
    .slice(1)
    .reduce((acc: Record<string, boolean>, dim) => {
      acc[dim] = false;
      return acc;
    }, {});

  legenSelectList.value.forEach((item) => {
    legendSelected.value[item] = true;
  });

  isShowAll.value = legenSelectList.value.length === legenAllList.value.length;
  isIndeterminate.value =
    legenSelectList.value.length > 0 &&
    legenSelectList.value.length < legenAllList.value.length;

  let totalWidth = barStackChart.value.clientWidth;
  let singleSeriesWidth = Math.ceil((totalWidth - 140) / dataCount);
  const barMinWidth = 30;
  const dataZoomNum = Math.floor((totalWidth - 140) / (barMinWidth * 1));
  const dataZoomEnd = Math.floor((100 / dataCount) * dataZoomNum);

  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 chartColors = props.color?.length > 0 ? props.color : defaultColors;

  const option: echarts.EChartsOption = {
    dataset: dataset,
    tooltip: {
      triggerOn: "mousemove",
      confine: true,
      extraCssText:
        "border-radius: 4px;padding:5px 0px 5px 5px;white-space:normal;word-warp:break-word;max-width: 400px;",
      enterable: true,
      formatter: (params: any) => {
        const seriesName = params.name;
        let tooltip = `<div class='tooltip_content'>`;
        let title = seriesName;
        tooltip += `<div class='tooltip_title'>${title}</div>`;

        let rateLabel = (dataset.source[0] as string[]).slice(1);

        for (let i = 0; i < rateLabel.length; i++) {
          let labelName = rateLabel[i];
          let rate = params.value[i + 1];
          let list: any[] = [],
            rateNum = "",
            isShowTip = props.tooltipData?.length > 0;

          if (props.tooltipData?.length > 0) {
            const dataIndex = params.dataIndex;
            const itemTooltip = props.tooltipData?.[dataIndex]?.[i] ?? "";
            list = itemTooltip?.list ?? [];
            rateNum = itemTooltip?.rateNum ?? "-";
          }

          if (isShowTip) {
            tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:${chartColors[i]}'></span>${labelName}：${rate == "-" ? "-" : rate + "%"}，${rateNum}人</div>`;
            if (i == rateLabel.length - 1) {
              for (let j = 0; j < list.length; j++) {
                tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:#CCCCCC'></span>${list[j].label}：${list[j].value}</div>`;
              }
            }
          } else {
            tooltip += `<div class='tooltip_student'><span class='tooltip_rect_icon' style='background:${chartColors[i]}'></span>${labelName}：${rate == "-" ? "-" : rate + "%"}</div>`;
          }
        }
        tooltip += `</div>`;
        return tooltip;
      },
    },
    legend: {
      show: true,
      top: '6px',
      left: props.showCheckBox ? "110px" : "0px",
      itemGap: 20,
      itemHeight: 10,
      itemWidth: 20,
      textStyle: { fontSize: 12, color: "#333" },
      selectedMode: true,
      selected: legendSelected.value,
      formatter: (name: string) => name,
    },
    grid: {
      top: 50,
      left: 40,
      right: 60,
      bottom: 0,
      containLabel: true,
    },
    dataZoom: singleSeriesWidth < barMinWidth ? dataZoom : null,
    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: function (value: string) {
          const valueWidth = value.length * 14;
          if (valueWidth > singleSeriesWidth) {
            if (singleSeriesWidth < 100) {
              if (valueWidth > 80) {
                return value.slice(0, 2) + "..." + value.slice(-3);
              } else {
                return value;
              }
            } else {
              let maxLength = Math.floor(singleSeriesWidth / 14) - 1;
              return value.slice(0, maxLength) + "...";
            }
          } else {
            return value;
          }
        },
      },
      tooltip: {
        show: true,
        formatter: function (params: any) {
          return params.value;
        },
      },
    },
    series: (dataset.source[0] as string[]).slice(1).map(function (dim, index) {
      const color = chartColors[index];
      return {
        type: "bar",
        stack: "total",
        barMaxWidth: 50,
        label: {
          show: singleSeriesWidth > 22,
          position: "inside",
          color: "#fff",
          fontSize: 12,
          formatter: function (params: any) {
            if (params.value[params.seriesIndex + 1] == 0) {
              return "";
            } else {
              return params.value[params.seriesIndex + 1] + "%";
            }
          },
        },
        itemStyle: { color: color },
      };
    }),
  };

  myChart.value.setOption(option);
  myChart.value.on("legendselectchanged", HandleLegendSelectChanged);

  if (props.isClick) {
    // const containerWidth = barStackChart.value.offsetWidth;
    const xAxisDataLength = props.data.length - 1;
    const gridRect = myChart.value
      .getModel()
      .getComponent("grid")
      .coordinateSystem.getRect();
    const singleLabelWidth = gridRect.width / xAxisDataLength;

    myChart.value.on("click", (params: any) => {
      if (params.seriesType === "bar") {
        let pixelPosition = myChart.value!.convertToPixel(
          { xAxisIndex: 0 },
          params.name,
        );
        myChart.value!.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);
      }
    });

    let defaultPixelPosition = myChart.value.convertToPixel(
      { xAxisIndex: 0 },
      props.data[1][0],
    );
    myChart.value.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 HandleLegendSelectChanged = (params: any) => {
  const selected = params.selected;
  legenSelectList.value = [];
  for (let i = 0; i < legenAllList.value.length; i++) {
    if (selected[legenAllList.value[i]] === true) {
      legenSelectList.value.push(legenAllList.value[i]);
    }
  }
  isShowAll.value = legenSelectList.value.length === legenAllList.value.length;
  isIndeterminate.value =
    legenSelectList.value.length > 0 &&
    legenSelectList.value.length < legenAllList.value.length;
};

const handleResize = throttle(() => {
  nextTick(() => {
    myChart.value?.resize();
  });
}, 500);

const ToggleChangeAll = (value: boolean | string | number) => {
  const isChecked = value === true;
  if (isChecked) {
    legenSelectList.value = [...legenAllList.value];
    isIndeterminate.value = false;
  } else {
    legenSelectList.value = [];
    isIndeterminate.value = false;
  }
  LoadEchart();
};

// ================= Watch =================
watch(
  () => props.data,
  () => {
    initLegenSelectList();
    LoadEchart();
  },
  { deep: true },
);

// ================= Lifecycle =================
onMounted(() => {
  window.addEventListener("resize", handleResize);
  initLegenSelectList();
  LoadEchart();
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
  if (myChart.value) {
    myChart.value.dispose();
  }
});
</script>

<style lang="scss" scoped>
</style>
