<!-- SidePanelItem.vue -->
<!-- 
  出入库水温图表组件
  功能：展示水库入库水温和出库水温的时序变化曲线
  数据来源：inOutOneGetKendoListCust接口
  特性：支持月份选择、站点筛选、数据缩放、空值断开显示
-->
<template>
    <SidePanelItem title="出入库水温" :moreSelect="select" :scopeDate="scopeDate" @update-values="handlePanelChange1">
        <!-- ECharts图表容器 -->
        <a-spin :spinning="loading" tip="加载中...">
            <div v-show="showemit && !loading" ref="chartContainer" class="chart-container"></div>
            <div v-show="!showemit && !loading" class="chart-container">
                <a-empty />
            </div>
        </a-spin>
    </SidePanelItem>
</template>

<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';
import dayjs from 'dayjs';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { getVmsstbprpt, inOutOneGetKendoListCust } from '@/api/sw';
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";

// ==================== 组件基础配置 ====================
// 定义组件名(便于调试和递归)
defineOptions({
    name: 'churukushuiwenMod'
});

// ==================== 状态管理初始化 ====================
const JidiSelectEventStore = useJidiSelectEventStore(); // 基地选择事件Store

// ==================== DOM引用与图表实例 ====================
const chartContainer = ref<HTMLDivElement | null>(null); // 图表容器DOM引用
let chartInstance: echarts.ECharts | null = null; // ECharts实例
const currentMonth = new Date().toISOString().slice(0, 7); // 当前月份(格式: YYYY-MM)
const chartDataLoaded = ref(false); // 数据加载状态标志,防止重复请求

// ==================== 加载状态与显示控制 ====================
const showemit = ref(false); // 控制图表是否显示
const loading = ref(false); // 控制加载状态

// ==================== 下拉框配置(站点选择) ====================
const select = ref({
    show: true,           // 是否显示下拉框
    value: '',            // 当前选中值(站点编码)
    options: [],          // 下拉选项列表
    picker: undefined,    // 选择器类型(未使用)
    format: undefined,    // 格式化字符串(未使用)
});

// ==================== 日期范围选择器配置 ====================
const scopeDate = ref({
    show: true,                          // 是否显示日期选择器
    value: [currentMonth, currentMonth] as any, // 默认选中当前月份范围（使用 as any 绕过类型检查）
    format: "YYYY-MM",                   // 显示格式
    picker: "month" as const,            // 选择器类型:月份选择
    options: [],                         // 可选日期范围(未使用)
});

// ==================== 业务变量 ====================
const baseid = ref(''); // 当前选中的基地ID

// ==================== 基地列表数据(硬编码) ====================
const jiDiList: any = ref([
    {
        "baseid": "all",
        "basename": "当前全部",
        "id": "9BFEC848-83EA-AD22-6DE2-10E969476693"
    },
    {
        "baseid": "01",
        "basename": "金沙江干流",
        "id": "A33040B7-8977-D9F1-5E02-D7F0241AB8AA"
    },
    {
        "baseid": "02",
        "basename": "雅砻江干流",
        "id": "C63D6020-995D-FE97-2F4A-F619A7142C79"
    },
    {
        "baseid": "03",
        "basename": "大渡河干流",
        "id": "CCB0766B-F1D4-7DD6-650F-5C556B7231B3"
    },
    {
        "baseid": "04",
        "basename": "乌江干流",
        "id": "E8A66641-B4F4-CC85-0815-38C5B2F93DBD"
    },
    {
        "baseid": "05",
        "basename": "长江上游干流",
        "id": "E02C11E9-CEA5-A030-202F-3BFE84465D03"
    },
    {
        "baseid": "10",
        "basename": "湘西",
        "id": "B1D1D52D-CEEF-6DC4-27DF-9990EB572F8D"
    },
    {
        "baseid": "08",
        "basename": "黄河上游干流",
        "id": "BC6AF135-263D-09A9-D5CA-C99B2598FE6E"
    },
    {
        "baseid": "09",
        "basename": "黄河中游干流",
        "id": "60EEEC28-128F-A2A8-44F3-6EAAC8FD8BB6"
    },
    {
        "baseid": "06",
        "basename": "南盘江-红水河",
        "id": "7BB9A8F4-34B5-42B4-A7FC-CE910AD7F203"
    },
    {
        "baseid": "12",
        "basename": "东北",
        "id": "47F8EF06-924E-E161-FCAF-62A66BBF252D"
    },
    {
        "baseid": "07",
        "basename": "澜沧江干流",
        "id": "A966A4C9-278C-B0DA-2B97-2D10B7A6E96A"
    },
    {
        "baseid": "13",
        "basename": "怒江干流",
        "id": "FA89E8CB-67A8-76DA-DC1E-23AE4C54F9E4"
    },
    {
        "baseid": "11",
        "basename": "闽浙赣",
        "id": "CD98F995-EEB2-1021-D807-DA1B1AD9E49A"
    },
    {
        "baseid": "other",
        "basename": "其他",
        "id": "AFBDFC67-B955-4EFD-959A-014CFB59EBFC"
    }
])

// ==================== 数据处理函数 ====================

/**
 * 转换图表数据格式
 * 将后端返回的扁平数据结构转换为ECharts所需的双线数据格式
 * @param rawData - 原始数据数组,包含tm(时间)、dwtp(类型:IWT/DWT)、wt(水温)字段
 * @returns 包含日期数组、入库水温数组、出库水温数组的对象
 */
function transformChartData(rawData: any[]) {
    // 1. 提取所有唯一日期并排序
    const dateSet = new Set<string>()
    rawData.forEach(item => {
        const date = item.tm?.split(' ')[0] // "2026-04-01 00:00:00" -> "2026-04-01"
        if (date) dateSet.add(date)
    })
    const dates = Array.from(dateSet).sort()

    // 2. 构建两条线的数据(入库水温和出库水温)
    const iwtData: (number | null)[] = []  // 入库水温(Inlet Water Temperature)
    const dwtData: (number | null)[] = []  // 出库水温(Discharge Water Temperature)

    dates.forEach(date => {
        // 查找该日期的入库水温(dwtp='IWT')
        const iwtItem = rawData.find(item =>
            item.tm?.startsWith(date) && item.dwtp === 'IWT'
        )
        // 保留一位小数,缺失则填null(曲线断开)
        iwtData.push(iwtItem ? Number(iwtItem.wt.toFixed(1)) : null)

        // 查找该日期的出库水温(dwtp='DWT')
        const dwtItem = rawData.find(item =>
            item.tm?.startsWith(date) && item.dwtp === 'DWT'
        )
        // 保留一位小数,缺失则填null(曲线断开)
        dwtData.push(dwtItem ? Number(dwtItem.wt.toFixed(1)) : null)
    })

    return { dates, iwtData, dwtData }
}

/**
 * 计算Y轴显示范围
 * 基于数据最小值和最大值,上下各扩展0.2的缓冲空间
 * @param data - 水温数据数组(可能包含null值)
 * @returns Y轴的最小值和最大值对象
 */
function calculateYAxisRange(data: (number | null)[]) {
    // 过滤出有效数值
    const validValues = data.filter(v => v !== null) as number[]
    if (validValues.length === 0) return { min: 0, max: 10 } // 无数据时返回默认范围

    const min = Math.min(...validValues)
    const max = Math.max(...validValues)

    // 上下各扩展0.2,避免曲线贴边
    return {
        min: Number((min - 0.2).toFixed(1)),  // 最小值减0.2
        max: Number((max + 0.2).toFixed(1))   // 最大值加0.2
    }
}

/**
 * 计算X轴刻度间隔
 * 确保最多显示4个刻度标签,避免标签重叠
 * @param dateCount - 日期总数
 * @returns X轴刻度间隔值(interval属性)
 */
function calculateXAxisInterval(dateCount: number): number {
    if (dateCount <= 4) return 0  // 数据点≤4时,显示所有刻度
    return Math.ceil(dateCount / 4) - 1  // 动态计算间隔,保证最多4个刻度
}
const paramsOne = ref({
    value: '',
    tm: [currentMonth, currentMonth]
})
/**
 * 获取图表数据
 * 调用后端接口获取出入库水温数据,并触发图表更新
 */
async function fetchChartData() {
    if (loading.value) return; // 防止重复请求
    
    loading.value = true; // 开始请求前设置loading
    
    try {
        // 动态计算时间范围（考虑不同月份的实际天数）
        const startDate = paramsOne.value.tm[0] + '-01 00:00:00';
        const endDate = dayjs(paramsOne.value.tm[1]).endOf('month').format('YYYY-MM-DD') + ' 23:59:59';
        
        // 构建查询参数(固定参数,后续可扩展为动态)
        const params = {
            filter: {
                logic: "and",
                filters: [
                    {
                        // OR逻辑:查询入库或出库水温
                        logic: "or",
                        filters: [
                            { field: "engDwtCode", operator: "eq", value: paramsOne.value.value }, // 出库站点编码
                            { field: "engIwtCode", operator: "eq", value: paramsOne.value.value }  // 入库站点编码
                        ]
                    },
                    // 时间范围过滤
                    { field: "dt", operator: "gte", dataType: "date", value: startDate },
                    { field: "dt", operator: "lte", dataType: "date", value: endDate }
                ]
            }
        }

        // 调用API获取数据
        const res = await inOutOneGetKendoListCust(params)
        const rawData = res?.data?.data || []

        console.log('原始数据:', rawData)

        // 根据数据长度决定showemit
        if (rawData.length > 0) {
            showemit.value = true; // 有数据则显示图表
            
            // 转换数据格式
            const { dates, iwtData, dwtData } = transformChartData(rawData)

            console.log('转换后的数据:', { dates, iwtData, dwtData })

            // 数据就绪后初始化或更新图表
            setTimeout(() => {
                if (!chartInstance) {
                    initChartWithData(dates, iwtData, dwtData); // 带数据初始化
                } else {
                    updateChart(dates, iwtData, dwtData, 0); // 已有实例则更新
                }
                
                // 强制重绘,确保图表尺寸正确适配容器
                setTimeout(() => {
                    if (chartInstance) {
                        chartInstance.resize();
                    }
                }, 50);
            }, 50);

        } else {
            showemit.value = false; // 无数据显示空状态
        }

        chartDataLoaded.value = true; // 标记数据已加载

    } catch (error) {
        console.error('获取图表数据失败:', error);
        showemit.value = false; // 出错也显示空状态
        chartDataLoaded.value = true; // 即使失败也标记为已加载,避免重复请求
    } finally {
        loading.value = false; // 无论成功失败都关闭loading
    }
}

/**
 * 带数据初始化图表
 * @param dates - 日期数组
 * @param iwtData - 入库水温数据
 * @param dwtData - 出库水温数据
 */
const initChartWithData = (dates: string[], iwtData: (number | null)[], dwtData: (number | null)[]) => {
    if (!chartContainer.value) return;
    
    const containerHeight = chartContainer.value.offsetHeight;
    if (containerHeight === 0) {
        setTimeout(() => initChartWithData(dates, iwtData, dwtData), 100);
        return;
    }
    
    chartInstance = echarts.init(chartContainer.value);
    updateChart(dates, iwtData, dwtData, 0);
};

/**
 * 更新图表配置
 * 根据处理后的数据动态生成ECharts配置项
 * @param dates - 日期数组(X轴数据)
 * @param iwtData - 入库水温数据数组
 * @param dwtData - 出库水温数据数组
 * @param yAxisMax - 废弃参数,保留以兼容旧代码
 */
function updateChart(dates: string[], iwtData: (number | null)[], dwtData: (number | null)[], yAxisMax: number) {
    if (!chartInstance) {
        console.warn('图表实例未初始化')
        return
    }

    try {
        // ==================== 动态计算坐标轴范围 ====================
        const xAxisInterval = calculateXAxisInterval(dates.length) // X轴刻度间隔
        const { min: yAxisMin, max: yAxisMaxValue } = calculateYAxisRange([...iwtData, ...dwtData]) // Y轴范围

        console.log('X轴间隔:', xAxisInterval, 'Y轴范围:', { min: yAxisMin, max: yAxisMaxValue })

        // ==================== ECharts配置项 ====================
        const option = {
            // 提示框配置
            tooltip: {
                trigger: 'axis', // 触发类型:坐标轴触发
                backgroundColor: 'rgba(50, 50, 50, 0.9)', // 背景色
                borderColor: 'transparent', // 边框透明
                textStyle: {
                    color: '#fff', // 文字颜色
                    fontSize: 14 // 字体大小
                },
                axisPointer: {
                    type: 'line', // 指示器类型:直线
                    lineStyle: {
                        color: 'rgba(91, 143, 249, 0.15)', // 指示线颜色
                        width: 30, // 指示线宽度
                        type: 'solid' // 线型:实线
                    }
                },
                // 自定义提示框内容
                formatter: function (params: any) {
                    if (!params || params.length === 0) return '';
                    const date = params[0].name; // 获取日期
                    let result = `<div style="font-weight: bold; margin-bottom: 8px; font-size: 14px;">${date}</div>`;
                    params.forEach((item: any) => {
                        // 空值显示'-',符合项目规范
                        const value = item.value !== null && item.value !== undefined ? `${item.value}°C` : '-'
                        result += `<div style="display: flex; align-items: center; gap: 6px; margin: 4px 0; font-size: 14px;">
              <span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color};"></span>
              <span>${item.seriesName}</span>
              <span style="font-weight: bold; margin-left: auto;">${value}</span>
            </div>`;
                    });
                    return result;
                }
            },

            // 标题配置
            title: {
                text: '水温(°C)', // 标题文本
                left: 17, // 左侧位置
                top: 13, // 顶部位置
                textStyle: {
                    fontSize: 13,
                    color: '#000000',
                    fontWeight: 'normal'
                }
            },

            // 图例配置
            legend: {
                data: ['入库水温', '出库水温'], // 图例项
                top: 13, // 顶部对齐
                left: 'center', // 水平居中
                itemWidth: 10, // 图例图标宽度
                itemHeight: 10, // 图例图标高度
                itemGap: 20, // 图例间距
                textStyle: {
                    fontSize: 13,
                    color: '#000000'
                }
            },

            // 网格配置(图表区域边距)
            grid: {
                left: '10%',
                right: '5%',
                top: '15%',
                bottom: '10%'
            },

            // X轴配置
            xAxis: {
                type: 'category', // 类目轴
                data: dates, // 日期数据
                boundaryGap: true, // 两侧留白
                interval: xAxisInterval,  // 动态刻度间隔,最多显示4个标签
                axisLine: {
                    show: true,
                    lineStyle: {
                        color: '#000000' // 轴线颜色
                    }
                },
                axisTick: {
                    show: false // 隐藏刻度线
                },
                axisLabel: {
                    color: '#000000', // 标签颜色
                    fontSize: 13, // 字体大小
                    margin: 10 // 标签与轴线距离
                },
                splitLine: {
                    show: true, // 显示分割线
                    lineStyle: {
                        color: '#bfbfbf', // 分割线颜色
                        type: 'solid' // 实线
                    }
                }
            },

            // 数据缩放配置(鼠标滚轮缩放)
            dataZoom: [
                {
                    type: 'inside', // 内置型数据区域缩放
                    start: 0, // 起始位置0%
                    end: 100, // 结束位置100%
                    minValueSpan: 2, // 最小显示2个数据点
                    zoomOnMouseWheel: true, // 允许滚轮缩放
                    moveOnMouseMove: true, // 允许鼠标拖拽平移
                    moveOnMouseWheel: false, // 滚轮不触发平移
                    zoomLock: false, // 不锁定缩放比例
                    throttle: 50 // 节流50ms
                }
            ],

            // Y轴配置
            yAxis: {
                type: 'value', // 数值轴
                min: yAxisMin, // 动态最小值(数据最小值-0.2)
                max: yAxisMaxValue, // 动态最大值(数据最大值+0.2)
                scale: true,  // 自适应缩放,不强制从0开始
                axisLine: {
                    show: true,
                    lineStyle: {
                        color: '#000000',
                        width: 1
                    }
                },
                axisTick: {
                    show: true, // 显示刻度线
                    lineStyle: {
                        color: '#000000',
                        width: 1
                    },
                    length: 4 // 刻度线长度
                },
                axisLabel: {
                    color: '#000000',
                    fontSize: 12,
                    formatter: '{value}' // 标签格式
                },
                splitLine: {
                    show: true, // 显示网格线
                    lineStyle: {
                        color: '#bfbfbf',
                        type: 'solid'
                    }
                }
            },

            // 系列数据配置(两条折线)
            series: [
                {
                    name: '入库水温', // 系列名称
                    type: 'line', // 图表类型:折线图
                    smooth: true, // 平滑曲线
                    symbol: 'circle', // 数据点形状:圆形
                    symbolSize: 4, // 数据点大小
                    connectNulls: true,  // 关键:不连接空值,实现曲线断开效果
                    lineStyle: {
                        width: 2, // 线宽
                        color: '#4b79ab' // 线条颜色:蓝色
                    },
                    itemStyle: {
                        color: '#4b79ab' // 数据点颜色
                    },
                    data: iwtData // 入库水温数据
                },
                {
                    name: '出库水温', // 系列名称
                    type: 'line', // 图表类型:折线图
                    smooth: true, // 平滑曲线
                    symbol: 'circle', // 数据点形状:圆形
                    symbolSize: 4, // 数据点大小
                    connectNulls: true, // 不连接空值,实现断开效果
                    lineStyle: {
                        width: 2, // 线宽
                        color: '#78c300' // 线条颜色:绿色
                    },
                    itemStyle: {
                        color: '#78c300' // 数据点颜色
                    },
                    data: dwtData // 出库水温数据
                }
            ]
        };

        // 应用配置到图表实例
        chartInstance.setOption(option, true); // true表示完全替换配置
        console.log('图表更新成功')

        // 强制重绘,确保图表尺寸正确适配容器
        setTimeout(() => {
            if (chartInstance) {
                chartInstance.resize(); // 重新计算图表尺寸
            }
        }, 50);

    } catch (error) {
        console.error('更新图表失败:', error)
    }
}

// ==================== 生命周期钩子 ====================

/**
 * 组件挂载时执行
 * 初始化图表并获取数据
 */
onMounted(() => {
    // 延迟100ms初始化,确保DOM渲染完成
    setTimeout(() => {
        if (chartContainer.value) {
            // fetchChartData(); // 先获取真实数据
            window.addEventListener('resize', handleResize); // 监听窗口大小变化
        }
    }, 100);
});

/**
 * 组件卸载时执行
 * 清理资源,防止内存泄漏
 */
onUnmounted(() => {
    if (chartInstance) {
        chartInstance.dispose(); // 销毁图表实例
        chartInstance = null;
    }
    window.removeEventListener('resize', handleResize); // 移除事件监听
});

/**
 * 窗口大小变化处理函数
 * 自适应调整图表尺寸
 */
const handleResize = () => {
    if (chartInstance) {
        chartInstance.resize(); // 重新计算图表尺寸
    }
};

// ==================== 事件处理函数 ====================

/**
 * SidePanelItem面板变化回调
 * 处理下拉框和日期选择器的值变化
 * @param data - 包含moreSelect(下拉框值)和datetime(日期范围)的对象
 */
const handlePanelChange1 = (data: any) => {
    // console.log('当前所有控件状态:', data);
    // debugger
    // TODO: 后续可扩展联动逻辑
    if (data.moreSelect) {
        paramsOne.value.value = data.moreSelect;
    }
    paramsOne.value.tm = data.scopeDate
    fetchChartData()
};

/**
 * 获取站点下拉选项数据
 * 根据选中的基地ID查询对应的站点列表
 */
const getselsectData = async () => {
    loading.value = true; // 开始加载站点数据
    
    try {
        let params = {
            "filter": {
                "logic": "and",
                "filters": [
                    // 如果baseid不是'all',则添加基地过滤条件
                    baseid.value != 'all' ? {
                        "field": "baseId",
                        "operator": "eq",
                        "dataType": "string",
                        "value": baseid.value
                    } : null,
                    // 站点类型过滤:只查询ENG类型站点
                    {
                        "field": "sttpCode",
                        "operator": "contains",
                        "dataType": "string",
                        "value": "ENG"
                    },
                    // 只查询有效站点(dtin=1)
                    {
                        "field": "dtin",
                        "operator": "eq",
                        "dataType": "string",
                        "value": 1
                    }
                ].filter(Boolean) // 过滤掉null值
            },
            "sort": [
                // 如果是'all',按基地排序;否则不排序
                baseid.value == 'all' ? {
                    "field": "baseStepSort",
                    "dir": "asc"
                } : null,
                {
                    "field": "rvcdStepSort",
                    "dir": "asc"
                },
                {
                    "field": "siteStepSort",
                    "dir": "asc"
                }
            ].filter(Boolean), // 过滤掉null值
            "select": [
                "stcd",      // 站点编码
                "stnm",      // 站点名称
                "lgtd",      // 经度
                "lttd",      // 纬度
                "siteStepSort", // 站点排序
                "baseId",    // 基地ID
                "baseName"   // 基地名称
            ]
        }

        // 调用API获取站点数据
        const res = await getVmsstbprpt(params)
        console.log('res', res)
        const data = res?.data?.data || res?.data
        const obj: any = {}

        if (data) {
            // 将扁平数据转换为树形结构(按基地分组)
            data.map((e) => {
                if (obj[e.baseId]) {
                    // 如果基地已存在,添加子节点
                    obj[e.baseId] = { ...obj[e.baseId], children: [...obj[e.baseId].children, { ...e, value: e.stcd, title: e.stnm }] }
                } else {
                    // 创建新的基地节点
                    obj[e.baseId] = { value: e.baseId, title: e.baseName, selectable: false, key: e.baseId, children: [{ ...e, value: e.stcd, title: e.stnm }] }
                }
            })

            // 转换为数组并按jiDiList顺序排序
            let treeData: any = []
            const dataMapNameArr: any = Object.entries(obj).map(([, v]) => v)
            treeData = dataMapNameArr?.sort((a: any, b: any) => {
                const indexA = jiDiList.value.findIndex(item => item.baseid === a.value);
                const indexB = jiDiList.value.findIndex(item => item.baseid === b.value);
                return indexA - indexB;
            })
            console.log('treeData', treeData)

            // 更新下拉框选项
            select.value.options = treeData

            // 设置默认选中值
            if (baseid.value == 'all') {
                select.value.value = '008640203800000001' // 默认选中第一个站点
            } else {
                select.value.value = treeData?.[0]?.children[0]?.value // 选中当前基地的第一个站点
            }
        }
    } catch (error) {
        console.error('获取站点数据失败:', error);
    } finally {
        loading.value = false; // 关闭loading
    }
}

// ==================== Watch监听器 ====================

/**
 * 监听基地选择变化
 * 当用户切换基地时,重新加载站点下拉选项
 */
watch(
    () => JidiSelectEventStore.selectedItem, // 监听Store中的选中项
    (newVal) => {
        baseid.value = newVal.wbsCode; // 更新基地ID
        getselsectData() // 重新获取站点数据
    },
    { deep: true, immediate: true } // 深度监听,立即执行
);
</script>

<style lang="scss" scoped>
/* 图表容器样式 */
.chart-container {
    width: 100%;
    height: 252px;
     display: flex;
  justify-content: center;
  align-items: center;
    /* 固定高度252px */
}
:deep(.ant-spin-nested-loading ){
  height: 252px !important;
}
</style>