<template>
    <div class="echart_content">
        <div class="is_show_all" v-if="showCheckBox">
            <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="ChangeCheckAll">
                显示全部
            </el-checkbox>
        </div>
        <div class="echart_type">
            <div class="chart_icon_item" :class="chartType === 'line_chart' ? 'line_chart_cur' : 'line_chart'"
                @click="ChangeChartType('line_chart')">
                折线图
            </div>
            <div class="chart_icon_item" :class="chartType === 'vertical_bar' ? 'vertical_bar_cur' : 'vertical_bar'
                " @click="ChangeChartType('vertical_bar')">
                柱状图
            </div>
        </div>
        <div ref="line_chart" class="chart_box"></div>
    </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
import { throttle } from "lodash-es";
import * as echarts from "echarts";
import type { ECharts } from "echarts";

// 类型定义
type ChartType = "line_chart" | "vertical_bar";

interface LegendSelected {
    [key: string]: boolean;
}

// Props 定义
const props = defineProps({
    gridRight: { type: Number, default: 0 },
    showCheckBox: { type: Boolean, default: true },
    extraText: { type: Boolean, default: true },
    datax: {
        type: Array<string>,
        default: () => [
            "G10",
            "G9",
            "G8",
            "G7",
            "G6",
            "G5",
            "G4",
            "G3",
            "G2",
            "G1",
        ],
    },
    datay: {
        type: Array<Array<number>>,
        default: () => [
            [12, 5, 8, 10, 15, 7, 9, 11, 13, 10],
            [6, 14, 9, 10, 12, 8, 7, 11, 15, 8],
            [5, 10, 15, 7, 9, 12, 8, 13, 14, 7],
        ],
    },
    tooltipData: { type: Array<any>, default: () => [] },
    colors: { type: Array<string>, default: () => [] },
    unit: { type: String, default: "" },
    title: { type: Array<string>, default: () => [] },
    isSetMarkNumber: { type: Boolean, default: false },
    markNumber: { type: Array<number>, default: () => [65] },
    isSmooth: { type: Boolean, default: false },
    showMarkLine: { type: Boolean, default: false },
    showBackground: { type: Boolean, default: true },
    isShowLabel: { type: Boolean, default: true },
    showMarkPoint: { type: Boolean, default: false },
    legendList: { type: Array<string>, default: () => [] },
    hideOverlap: { type: Boolean, default: false },
});

// 响应式数据
const line_chart = ref<HTMLElement | null>(null);
let echartInstance: ECharts | null = null;

const checkAll = ref<boolean>(true);
const isIndeterminate = ref<boolean>(false);
const legendSelected = ref<LegendSelected>({});
const legenSelectList = ref<string[]>([]);
const legenAllList = ref<string[]>([...props.title]);
const chartType = ref<ChartType>("line_chart");
const dataZoomEnd = ref<number>(0);
const dataZoomNum = ref<number>(5);

// 监听数据变化
watch(
    () => props.datay,
    () => {
        LoadEchart();
    },
    { deep: true },
);

// 辅助线配置
const markLine = (index: number) => {
    if (!props.showMarkLine) return {};
    return {
        data: [
            {
                type: "average",
                name: "平均值",
                yAxis: props.isSetMarkNumber ? props.markNumber[index] : null,
            },
        ],
        label: {
            position: "end",
            formatter: (params: any) =>
                props.isSetMarkNumber ? props.markNumber[index] : params.value,
        },
        lineStyle: { type: "dashed", color: props.colors[index] },
    };
};

// 切换图表类型
const ChangeChartType = (val: ChartType) => {
    chartType.value = val;
    LoadEchart();
};

// 初始化图表
const LoadEchart = () => {
    if (!line_chart.value) return;
    if (echartInstance) {
        echartInstance.dispose();
        echartInstance = null;
    }

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

    // 颜色补齐
    let customColors = [...props.colors];
    const colorsList = [
        "#5470C6",
        "#91CC75",
        "#FAC858",
        "#EE6666",
        "#73C0DE",
        "#3BA272",
        "#FC8452",
        "#9A60B4",
        "#EA7CCC",
        "#66C",
        "#C33",
        "#FC0",
        "#6C0",
        "#09C",
    ];
    while (customColors.length < props.title.length)
        customColors = customColors.concat(colorsList);

    // 图例选中状态
    legenAllList.value = [...props.title];
    legendSelected.value = props.title.reduce((acc, dim) => {
        acc[dim] = false;
        return acc;
    }, {} as LegendSelected);

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

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

    // 计算宽度与滚动条
    const numSeries = Object.keys(legendSelected.value).filter(
        (k) => legendSelected.value[k],
    ).length;
    const totalWidth = line_chart.value.clientWidth || 0;
    let isShowDataZoom = false;
    const barMinWidth = 30;
    dataZoomNum.value = Math.floor((totalWidth - 60) / (barMinWidth * numSeries));
    const echartWidth = (props.datax.length - 1) * barMinWidth * numSeries;
    let singleSeriesWidth =
        ((totalWidth - 60) / (props.datax.length - 1)) * numSeries - 60;
    dataZoomEnd.value = Math.floor(
        (100 / (props.datax.length - 1)) * dataZoomNum.value,
    );
    if (echartWidth > totalWidth) isShowDataZoom = true;
    if (isShowDataZoom) singleSeriesWidth = 25 * legenSelectList.value.length;

    // 滚动条配置
    const dataZoomConfig = isShowDataZoom
        ? {
            start: 0,
            end: dataZoomEnd.value,
            type: "slider",
            show: true,
            borderColor: "transparent",
            xAxisIndex: [0],
            height: 8,
            left: 20,
            right: 20,
            bottom: 0,
            fillerColor: "transparent",
            zoomLock: true,
            handleSize: "0",
            backgroundColor: "transparent",
            showDataShadow: false,
            showDetail: false,
            filterMode: "filter",
        }
        : [];

    const legendWidth = totalWidth - 270;
    const extraText = props.extraText ? "占比" : "";

    // 柱状图配置
    const barOption: echarts.EChartsOption = {
        tooltip: {
            trigger: "axis",
            axisPointer: { type: "line" },
            renderMode: "html",
            confine: true,
            extraCssText:
                "border-radius:4px; padding:5px; white-space:normal; max-width:400px;",
            enterable: true,
            formatter: (params: any) => {
                let tip = `<div class='tooltip_content'><div class='tooltip_title'>${params[0]?.name}</div>`;
                params.forEach((item: any) => {
                    const val = props.tooltipData.length
                        ? props.tooltipData[item.seriesIndex]?.[item.dataIndex] || ""
                        : `${item.value}${props.unit}`;
                    tip += `<div class='tooltip_student'>
                    <div class='tooltip_rect_icon' style='background:${item.color}'></div>
                    <div class='tooltip_student_name'>${item.seriesName}${extraText}：${val}</div>
                  </div>`;
                });
                return tip + "</div>";
            },
        },
        legend: {
            show: true,
            top: '6px',
            left: props.showCheckBox ? "110px" : "0px",
            width: legendWidth + "px",
            itemGap: 20,
            itemHeight: 10,
            itemWidth: 25,
            data: props.title,
            textStyle: { fontSize: 12, color: "#333" },
            selected: legendSelected.value,
            type: "scroll",
            pageButtonPosition: "end",
            orient: "horizontal",
        },
        dataZoom: dataZoomConfig,
        grid: { left: 30, right: 20, top: 50, bottom: 0, containLabel: true },
        xAxis: {
            type: "category",
            data: props.datax,
            boundaryGap: true,
            axisTick: { alignWithLabel: true },
            axisLabel: {
                interval: 0,
                rotate: singleSeriesWidth < 80 ? 45 : 0,
                fontSize: 14, 
                color: "#333",
                formatter: (val: string) => {
                    const w = val.length * 10;
                    if (w > singleSeriesWidth) return val.slice(0, 6) + "...";
                    return val;
                },
            },
        },
        yAxis: {
            type: "value",
            axisLabel: { formatter: `{value}${props.unit}`, fontSize: 14 },
            splitLine: { lineStyle: { color: "#E4E7ED" } },
            splitArea: { show: true, areaStyle: { color: ["#fafafa", "#fff"] } },
        },
        series: props.datay.map((data, i) => ({
            type: "bar",
            name: props.title[i],
            barGap: 0,
            barCategoryGap: "30%",
            barMinWidth: 20,
            barMaxWidth: 50,
            itemStyle: { color: customColors[i] },
            label: {
                show: true,
                position: "top",
                fontSize: 12,
                formatter: (p: any) => (p.value === 0 ? "" : `${p.value}人`),
            },
            markLine: markLine(i),
            data,
        })),
    };

    // 折线图配置
    const lineOption: echarts.EChartsOption = {
        tooltip: {
            trigger: "axis",
            axisPointer: { type: "line" },
            renderMode: "html",
            confine: true,
            extraCssText:
                "border-radius:4px; padding:5px; white-space:normal; max-width:400px;",
            enterable: true,
            formatter: (params: any) => {
                let tip = `<div class='tooltip_content'><div class='tooltip_title'>${params[0]?.name}</div>`;
                params.forEach((item: any) => {
                    const val = props.tooltipData.length
                        ? props.tooltipData[item.seriesIndex]?.[item.dataIndex] || ""
                        : `${item.value}${props.unit}`;
                    tip += `<div class='tooltip_student'>
                    <div class='tooltip_line_icon' style='background:${item.color}'></div>
                    <div class='tooltip_student_name'>${item.seriesName}${extraText}：${val}</div>
                  </div>`;
                });
                return tip + "</div>";
            },
        },
        legend: {
            show: true,
            top: '6px',
            left: props.showCheckBox ? "110px" : "0px",
            width: legendWidth + "px",
            itemGap: 20,
            itemHeight: 10,
            itemWidth: 25,
            data: props.title,
            textStyle: { fontSize: 12, color: "#333" },
            selected: legendSelected.value,
            type: "scroll",
            pageButtonPosition: "end",
            orient: "horizontal",
        },
        grid: { left: 30, right: 20, top: 50, bottom: 0, containLabel: true },
        xAxis: {
            type: "category",
            data: props.datax,
            boundaryGap: true,
            axisTick: { alignWithLabel: true },
            axisLabel: {
                interval: 0,
                hideOverlap: props.hideOverlap,
                rotate: totalWidth / props.datax.length < 80 ? 45 : 0,
                fontSize: 14,
                color: "#333",
                formatter: (val: string) => {
                    const w = val.length * 10;
                    if (w > singleSeriesWidth) return val.slice(0, 6) + "...";
                    return val;
                },
            },
        },
        yAxis: {
            type: "value",
            axisLabel: { formatter: `{value}${props.unit}`, fontSize: 14 },
            splitLine: { lineStyle: { color: "#E4E7ED" } },
            splitArea: { show: true, areaStyle: { color: ["#fafafa", "#fff"] } },
        },
        series: props.datay.map((data, i) => ({
            type: "line",
            name: props.title[i],
            symbol: "emptyCircle",
            showSymbol: true,
            symbolSize: 8,
            smooth: props.isSmooth,
            label: { show: false },
            markLine: markLine(i),
            markPoint: props.showMarkPoint
                ? { data: [{ type: "max" }, { type: "min" }] }
                : undefined,
            itemStyle: { color: customColors[i] },
            lineStyle: { width: 4 },
            data,
        })),
    };

    // 渲染
    chartType.value === "vertical_bar"
        ? echartInstance.setOption(barOption)
        : echartInstance.setOption(lineOption);

    echartInstance.on("legendselectchanged", HandleLegendSelectChanged);
};

// 图例切换
const HandleLegendSelectChanged = (params: any) => {
    const sel = params.selected;
    legenSelectList.value = legenAllList.value.filter((item) => sel[item]);
    LoadEchart();
};

// 全选
const ChangeCheckAll = (value: boolean) => {
    if (value) {
        legenSelectList.value = [...legenAllList.value];
        isIndeterminate.value = false;
    } else {
        legenSelectList.value = [];
    }
    LoadEchart();
};

// 窗口缩放
const HandleResize = throttle(async () => {
    await nextTick();
    LoadEchart();
}, 500);

// 生命周期
onMounted(() => {
    if (props.legendList.length) legenSelectList.value = [...props.legendList];
    LoadEchart();
    window.addEventListener("resize", HandleResize);
});

onBeforeUnmount(() => {
    window.removeEventListener("resize", HandleResize);
    echartInstance?.dispose();
});
</script>

<style lang="scss" scoped>
.echart_content {
    position: relative;
    width: 100%;
    margin: auto;
    min-height: 360px;
    height: auto;

    .is_show_all {
        position: absolute;
        top: 2px;
        left: 5px;
    }

    .chart_box {
        width: 100%;
        height: 400px;
    }

    .echart_type {
        position: absolute;
        right: 0;
        top: 8px;
        z-index: 7;
        display: flex;
        justify-content: flex-end;
        gap: 12px;

        .chart_icon_item {
            font-weight: 400;
            font-size: 14px;
            color: #909399;
            line-height: 16px;
            background-repeat: no-repeat;
            background-size: 16px 16px;
            background-position: 0 50%;
            text-indent: 20px;
            text-align: right;
            cursor: pointer;

            //折线图
            &.line_chart {
                background-image: url("@/assets/chart/line_chart.webp");
            }

            &.line_chart_cur {
                font-weight: 500;
                font-size: 14px;
                color: #2e64fa;
                background-image: url("@/assets/chart/line_chart_cur.webp");
            }

            &.vertical_bar {
                background-image: url("@/assets/chart/vertical_bar.webp");
            }

            &.vertical_bar_cur {
                font-weight: 500;
                font-size: 14px;
                color: #2e64fa;
                background-image: url("@/assets/chart/vertical_bar_cur.webp");
            }
        }
    }
}
</style>
