// composables/useWeatherChart.ts
import { ref, computed, watch, onBeforeUnmount, type Ref, type ShallowRef, shallowRef } from "vue";
import type { WeatherDataRow } from "./useWeatherStats";
import { rainLevelLabel } from "./useWeatherConstants";

// ---------- 类型 ----------

export interface FilterExtremes {
  maxRainYear: number | null;
  maxRain: number | null;
  maxTmaxYear: number | null;
  maxTmax: number | null;
  minTminYear: number | null;
  minTmin: number | null;
  maxTavgYear?: number;
  maxTavg?: number | null;
}

// ---------- 图表触发键（精确 diff，替代 deep watch） ----------

export interface ChartTriggerKey {
  dataHash: number; // weatherData.length 即可作为简易 hash
  filteredHash: number; // filteredRows.length
  showOnlyFiltered: boolean;
  hasActiveFilter: boolean;
  extremesVersion: number; // filterExtremes 变更时 +1
}

// ---------- Composable ----------

export function useWeatherChart(
  weatherData: Ref<WeatherDataRow[]>,
  filteredRows: Ref<WeatherDataRow[]>,
  showOnlyFiltered: Ref<boolean>,
  hasActiveFilter: Ref<boolean>,
  filterExtremes: Ref<FilterExtremes | null>,
  anchorMonth: Ref<number>,
  anchorDay: Ref<number>
) {
  const chartRef = ref<HTMLElement | null>(null);
  const chartInst: ShallowRef<any> = shallowRef(null);
  let chartResizeObserver: ResizeObserver | null = null;

  // ---------- 精确触发键（替代 deep watch） ----------

  const chartTrigger = computed<ChartTriggerKey>(() => ({
    dataHash: weatherData.value.length,
    filteredHash: filteredRows.value.length,
    showOnlyFiltered: showOnlyFiltered.value,
    hasActiveFilter: hasActiveFilter.value,
    extremesVersion: filterExtremes.value
      ? filterExtremes.value.maxRainYear +
        filterExtremes.value.maxTmaxYear +
        filterExtremes.value.minTminYear
      : 0
  }));

  // ---------- 构建 ECharts 配置 ----------

  const chartOptions = computed(() => {
    const month = anchorMonth.value;
    const day = anchorDay.value;
    const hasFilter = hasActiveFilter.value;
    const extremes = filterExtremes.value;

    // 源数据（倒序，使图表从左到右为时间递增）
    let src = [...weatherData.value].reverse();
    const matchSet = new Set(filteredRows.value.map((r) => r.year));

    if (showOnlyFiltered.value && hasFilter) {
      src = src.filter((d) => matchSet.has(d.year));
    }

    const effectiveMatchSet =
      showOnlyFiltered.value && hasFilter ? new Set(src.map((d) => d.year)) : matchSet;

    return buildChartOption(src, effectiveMatchSet, extremes, hasFilter, month, day);
  });

  // ---------- 渲染 ----------

  let renderTimer: ReturnType<typeof setTimeout> | null = null;

  function scheduleRender() {
    if (renderTimer) clearTimeout(renderTimer);
    renderTimer = setTimeout(() => {
      renderChart();
    }, 150);
  }

  async function renderChart() {
    if (!chartRef.value) return;

    // 确保 DOM 已渲染且有尺寸，避免 ECharts "invalid dom" 报错
    const { width, height } = chartRef.value.getBoundingClientRect();
    if (width === 0 || height === 0) {
      // DOM 未就绪，延迟重试
      scheduleRender();
      return;
    }

    // 动态按需加载 ECharts
    const echarts = await import("echarts");
    const mod = (echarts as any).default || echarts;

    if (chartInst.value) {
      chartInst.value.setOption(chartOptions.value, true);
    } else {
      chartInst.value = mod.init(chartRef.value);
      chartInst.value.setOption(chartOptions.value, true);

      chartResizeObserver = new ResizeObserver(() => {
        chartInst.value?.resize();
      });
      chartResizeObserver.observe(chartRef.value);
    }
  }

  function destroyChart() {
    if (renderTimer) clearTimeout(renderTimer);
    chartResizeObserver?.disconnect();
    chartResizeObserver = null;
    chartInst.value?.dispose();
    chartInst.value = null;
  }

  // ---------- 监听触发键变更 ----------

  watch(chartTrigger, () => {
    scheduleRender();
  });

  onBeforeUnmount(() => {
    destroyChart();
  });

  return {
    chartRef,
    chartOptions,
    renderChart,
    destroyChart
  };
}

// =============================================================================
//  buildChartOption（纯函数，零依赖）
// =============================================================================

function buildChartOption(
  src: WeatherDataRow[],
  matchedYears: Set<number>,
  extremes: FilterExtremes | null | undefined,
  hasFilter: boolean,
  month: number,
  day: number
) {
  const xData = src.map((d) => d.year);

  const isHit = (d: WeatherDataRow) => !hasFilter || matchedYears.has(d.year);

  const gradHit = {
    type: "linear" as const,
    x: 0,
    y: 0,
    x2: 0,
    y2: 1,
    colorStops: [
      { offset: 0, color: "#60a5fa" },
      { offset: 1, color: "#2563eb" }
    ]
  };

  const markPoints: any[] = [];
  const markPointsTmax: any[] = [];
  const markPointsTmin: any[] = [];
  const markPointsTavg: any[] = [];

  if (hasFilter && extremes) {
    addExtremeMarkers(src, extremes, markPoints, markPointsTmax, markPointsTmin, markPointsTavg);
  }

  const markLines: any[] = [];
  if (hasFilter) {
    for (let i = 0; i < src.length; i++) {
      if (matchedYears.has(src[i].year)) {
        markLines.push([
          { xAxis: i, yAxis: 0, symbol: "none" },
          {
            xAxis: i,
            yAxis: "max",
            symbol: "none",
            lineStyle: { color: "rgba(16,185,129,0.22)", width: 2, type: "dashed" as const },
            label: { show: false }
          }
        ]);
      }
    }
  }

  const rainData = src.map((d) => ({
    value: d.rainfall,
    itemStyle: {
      color: isHit(d) ? gradHit : "rgba(148,163,184,0.18)",
      borderRadius: [3, 3, 0, 0]
    }
  }));

  const mkSeries = (vals: number[], hitColor: string, dimColor: string, hitSize = 6, dimSize = 2) =>
    src.map((d, i) => ({
      value: vals[i],
      symbolSize: isHit(d) ? hitSize : dimSize,
      itemStyle: { color: isHit(d) ? hitColor : dimColor }
    }));

  const dateLabel = `${month}月${String(day).padStart(2, "0")}日`;

  return {
    tooltip: {
      trigger: "axis" as const,
      backgroundColor: "rgba(255,255,255,.96)",
      borderColor: "#e2e8f0",
      textStyle: { fontSize: 13 },
      formatter(ps: any[]) {
        const yr = ps[0]?.axisValue;
        const hit = !hasFilter || matchedYears.has(yr);
        const isExtreme =
          extremes &&
          (yr === extremes.maxRainYear ||
            yr === extremes.maxTmaxYear ||
            yr === extremes.minTminYear ||
            yr === extremes.maxTavgYear);
        let h = `<div style="font-weight:700;margin-bottom:4px">${yr}年 ${dateLabel}`;
        if (hit && hasFilter) h += " ✅";
        if (isExtreme) h += ' <span style="color:#7c3aed;font-size:11px">⭐极值年份</span>';
        h += "</div>";
        ps.forEach((p: any) => {
          h += `${p.marker} ${p.seriesName}: <b>${p.value}</b><br/>`;
        });
        return h;
      }
    },
    legend: { bottom: 0, textStyle: { fontSize: 12 } },
    grid: { top: "12%", bottom: "14%", left: "6%", right: "6%" },
    xAxis: {
      type: "category" as const,
      data: xData,
      axisLabel: { rotate: xData.length > 25 ? 45 : 0, fontSize: 11 }
    },
    yAxis: [
      {
        type: "value" as const,
        name: "降雨(mm)",
        nameTextStyle: { color: "#2563eb", fontWeight: 600 as const },
        splitLine: { lineStyle: { type: "dashed" as const, color: "#f1f5f9" } }
      },
      {
        type: "value" as const,
        name: "气温(℃)",
        position: "right" as const,
        scale: true,
        nameTextStyle: { color: "#ef4444", fontWeight: 600 as const },
        splitLine: { show: false }
      }
    ],
    series: [
      {
        name: "降雨量",
        type: "bar" as const,
        barMaxWidth: 20,
        data: rainData,
        markLine: { silent: true, symbol: ["none" as const, "none" as const], data: markLines },
        markPoint: { data: markPoints }
      },
      {
        name: "最高气温",
        type: "line" as const,
        yAxisIndex: 1,
        smooth: true,
        symbolSize: 0,
        lineStyle: { width: 2.5, color: "#ef4444" },
        data: mkSeries(
          src.map((d) => d.tmax),
          "#ef4444",
          "rgba(239,68,68,0.12)"
        ),
        markPoint: { data: markPointsTmax }
      },
      {
        name: "最低气温",
        type: "line" as const,
        yAxisIndex: 1,
        smooth: true,
        symbolSize: 0,
        lineStyle: { width: 2, color: "#3b82f6", type: "dashed" as const },
        data: mkSeries(
          src.map((d) => d.tmin),
          "#3b82f6",
          "rgba(59,130,246,0.12)",
          5,
          2
        ),
        markPoint: { data: markPointsTmin }
      },
      {
        name: "平均气温",
        type: "line" as const,
        yAxisIndex: 1,
        smooth: true,
        symbolSize: 0,
        lineStyle: { width: 2, color: "#f59e0b" },
        data: mkSeries(
          src.map((d) => d.tavg),
          "#f59e0b",
          "rgba(245,158,11,0.15)",
          5,
          2
        ),
        markPoint: { data: markPointsTavg }
      }
    ]
  };
}

// ---------- 极值标记 ----------

function addExtremeMarkers(
  src: WeatherDataRow[],
  extremes: FilterExtremes,
  rain: any[],
  tmax: any[],
  tmin: any[],
  tavg: any[]
) {
  if (extremes.maxRainYear != null && extremes.maxRain != null) {
    const idxRain = src.findIndex((d) => d.year === extremes.maxRainYear);
    if (idxRain >= 0) {
      rain.push({
        name: "最大降雨",
        coord: [idxRain, extremes.maxRain],
        value: `${extremes.maxRain}mm`,
        symbol: "circle",
        symbolSize: 8,
        itemStyle: { color: "#7c3aed" },
        label: {
          position: "top",
          offset: [0, -10],
          color: "#fff",
          fontSize: 12,
          fontWeight: 700,
          backgroundColor: "#7c3aed",
          padding: [4, 10],
          borderRadius: 4
        }
      });
    }
  }

  if (extremes.maxTmaxYear != null && extremes.maxTmax != null) {
    const idxTmax = src.findIndex((d) => d.year === extremes.maxTmaxYear);
    if (idxTmax >= 0) {
      tmax.push({
        name: "最高温",
        coord: [idxTmax, extremes.maxTmax],
        value: `${extremes.maxTmax}℃`,
        symbol: "circle",
        symbolSize: 8,
        itemStyle: { color: "#dc2626" },
        label: {
          position: "top",
          offset: [0, -10],
          color: "#fff",
          fontSize: 12,
          fontWeight: 700,
          backgroundColor: "#dc2626",
          padding: [4, 10],
          borderRadius: 4
        }
      });
    }
  }

  if (extremes.minTminYear != null && extremes.minTmin != null) {
    const idxTmin = src.findIndex((d) => d.year === extremes.minTminYear);
    if (idxTmin >= 0) {
      tmin.push({
        name: "最低温",
        coord: [idxTmin, extremes.minTmin],
        value: `${extremes.minTmin}℃`,
        symbol: "circle",
        symbolSize: 8,
        itemStyle: { color: "#1d4ed8" },
        label: {
          position: "bottom",
          offset: [0, 10],
          color: "#fff",
          fontSize: 12,
          fontWeight: 700,
          backgroundColor: "#1d4ed8",
          padding: [4, 10],
          borderRadius: 4
        }
      });
    }
  }

  if (extremes.maxTavgYear != null && extremes.maxTavg != null) {
    const idxTavg = src.findIndex((d) => d.year === extremes.maxTavgYear);
    if (idxTavg >= 0) {
      tavg.push({
        name: "最高平均温",
        coord: [idxTavg, extremes.maxTavg],
        value: `${extremes.maxTavg}℃`,
        symbol: "circle",
        symbolSize: 8,
        itemStyle: { color: "#f59e0b" },
        label: {
          position: "top",
          offset: [0, -10],
          color: "#fff",
          fontSize: 12,
          fontWeight: 700,
          backgroundColor: "#f59e0b",
          padding: [4, 10],
          borderRadius: 4
        }
      });
    }
  }
}
