"use client";

import React, { useEffect, useMemo, useRef, useState } from "react";
import { Box, Button, Chip, Tooltip, Typography } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { zhCN } from "@mui/x-data-grid/locales";
import {
  CheckCircleOutline as CheckCircleIcon,
  ErrorOutline as ErrorOutlineIcon,
  FormatListBulleted,
  InfoOutlined as InfoOutlinedIcon,
  Room as RoomIcon,
  ShowChart as ShowChartIcon,
} from "@mui/icons-material";
import ReactECharts from "echarts-for-react";
import dayjs from "dayjs";
import Feature from "ol/Feature";
import { GeoJSON } from "ol/format";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { Circle, Fill, Stroke, Style } from "ol/style";
import { bbox, featureCollection } from "@turf/turf";
import { useMap } from "@components/olmap/core/MapComponent";
import { queryFeaturesByIds } from "@/utils/mapQueryService";
import { BurstDetectionResult, BurstDetectionRow } from "./types";
import PanelEmptyState from "@components/olmap/common/PanelEmptyState";

export interface BurstDetectionResultsState {
  selectedDay: number | null;
}

export const createBurstDetectionResultsState =
  (): BurstDetectionResultsState => ({ selectedDay: null });

interface Props {
  result: BurstDetectionResult | null;
  state?: BurstDetectionResultsState;
  onStateChange?: (state: BurstDetectionResultsState) => void;
}

interface MetricCardProps {
  label: string;
  value: string;
  hint?: string;
  tone: "blue" | "orange" | "purple" | "green";
}

const toneStyles: Record<MetricCardProps["tone"], string> = {
  blue: "border-blue-200 from-blue-50 to-blue-100 text-blue-900",
  orange: "border-orange-200 from-orange-50 to-orange-100 text-orange-900",
  purple: "border-purple-200 from-purple-50 to-purple-100 text-purple-900",
  green: "border-green-200 from-green-50 to-green-100 text-green-900",
};

const MetricCard = ({ label, value, hint, tone }: MetricCardProps) => (
  <Box
    className={`rounded-lg border bg-gradient-to-br p-3 shadow-sm ${toneStyles[tone]}`}
  >
    <Typography variant="caption" className="mb-1 block font-semibold">
      {label}
    </Typography>
    <Typography variant="body2" className="font-bold">
      {value}
    </Typography>
    {hint ? (
      <Typography variant="caption" className="mt-0.5 block opacity-75">
        {hint}
      </Typography>
    ) : null}
  </Box>
);

const formatDateTime = (value?: string) =>
  value ? dayjs(value).format("YYYY-MM-DD HH:mm") : "-";

const EmptyState = () => (
  <PanelEmptyState
    icon={<ShowChartIcon />}
    title="尚未生成侦测结果"
    description="请在“侦测参数”中运行分析，或在“方案查询”中打开历史结果。"
  />
);

const DetectionResults: React.FC<Props> = ({ result, state, onStateChange }) => {
  const map = useMap();
  const highlightLayerRef = useRef<VectorLayer<VectorSource> | null>(null);
  const [highlightFeatures, setHighlightFeatures] = useState<Feature[]>([]);
  const [internalState, setInternalState] = useState<BurstDetectionResultsState>(
    createBurstDetectionResultsState,
  );
  const resultsState = state ?? internalState;
  const setSelectedDay = (selectedDay: number | null) => {
    const nextState = { selectedDay };
    if (state === undefined) setInternalState(nextState);
    onStateChange?.(nextState);
  };

  useEffect(() => {
    if (!map) return;
    const layer = new VectorLayer({
      source: new VectorSource(),
      style: new Style({
        stroke: new Stroke({ color: "#ef4444", width: 4 }),
        image: new Circle({
          radius: 7,
          fill: new Fill({ color: "#ef4444" }),
          stroke: new Stroke({ color: "#fff", width: 2 }),
        }),
        zIndex: 999,
      }),
      properties: {
        name: "爆管侦测高亮",
        value: "burst_detection_highlight",
        queryable: false,
      },
    });
    map.addLayer(layer);
    highlightLayerRef.current = layer;
    return () => {
      highlightLayerRef.current = null;
      map.removeLayer(layer);
    };
  }, [map]);

  useEffect(() => {
    const source = highlightLayerRef.current?.getSource();
    if (!source) return;
    source.clear();
    highlightFeatures.forEach((feature) => source.addFeature(feature));
  }, [highlightFeatures]);

  const sortedRows = useMemo(
    () => [...(result?.rows ?? [])].sort((a, b) => a.Day - b.Day),
    [result],
  );

  const timestampForRow = (row: BurstDetectionRow) => {
    if (row.Timestamp) return row.Timestamp;
    const start = dayjs(result?.scada_window?.start);
    return start.isValid() ? start.add(row.Day, "day").toISOString() : undefined;
  };

  const scoreThreshold = result?.summary.score_threshold ?? 0;
  const scoreSeries = sortedRows.map((row) => ({
        day: row.Day,
        value: [
          timestampForRow(row)
            ? dayjs(timestampForRow(row)).format("MM-DD HH:mm")
            : `第 ${row.Day} 天`,
          Number(row.Score.toFixed(4)),
        ],
        itemStyle: {
          color:
            row.Role === "target"
              ? row.IsBurst
                ? "#ef4444"
                : "#2563eb"
              : "#94a3b8",
        },
        symbolSize: row.Role === "target" ? 11 : 7,
      }));

  const rankingSeries = useMemo(
    () =>
      [...(result?.summary.latest_sensor_rankings ?? [])]
        .sort(
          (a, b) =>
            (a.standardized_deviation ?? a.latest_high_frequency_value) -
            (b.standardized_deviation ?? b.latest_high_frequency_value),
        )
        .map((item) => ({
          name: item.sensor_node,
          value: Number(
            (item.standardized_deviation ?? item.latest_high_frequency_value).toFixed(3),
          ),
        })),
    [result],
  );

  const locateSensors = async (sensorIds: string[]) => {
    if (!map || sensorIds.length === 0) return;
    let features = await queryFeaturesByIds(sensorIds, "geo_junctions_mat");
    if (features.length === 0) {
      features = await queryFeaturesByIds(sensorIds, "geo_junctions");
    }
    if (features.length === 0) return;
    setHighlightFeatures(features);
    const format = new GeoJSON();
    const geojsonFeatures = features.map((feature) =>
      format.writeFeatureObject(feature),
    );
    // @ts-ignore turf accepts OpenLayers GeoJSON feature objects
    const extent = bbox(featureCollection(geojsonFeatures));
    map.getView().fit(extent, {
      maxZoom: 18,
      duration: 1000,
      padding: [100, 100, 100, 100],
    });
  };

  if (!result) return <EmptyState />;

  const targetRow = sortedRows.find((row) => row.Role === "target") ?? sortedRows.at(-1);
  const isBurstDetected = result.summary.burst_detected;
  const targetRank = result.summary.target_rank;
  const excludedCount = result.data_quality?.excluded_sensors.length ?? 0;

  const chartOption = {
    tooltip: {
      trigger: "axis",
      formatter: (params: Array<{ data: { day: number; value: [string, number] } }>) => {
        const data = params[0]?.data;
        return data
          ? `${data.value[0]}<br/>${data.day === 15 ? "目标时刻" : "参考日"}<br/>异常分数：${data.value[1]}`
          : "-";
      },
    },
    grid: { top: 30, left: 48, right: 20, bottom: 48 },
    xAxis: {
      type: "category",
      name: "同刻日期",
      boundaryGap: false,
      data: scoreSeries.map((item) => item.value[0]),
      axisLabel: { fontSize: 10, interval: 2, rotate: 25 },
    },
    yAxis: { type: "value", name: "异常分数", axisLabel: { fontSize: 10 } },
    series: [
      {
        type: "line",
        data: scoreSeries,
        lineStyle: { color: "#94a3b8", width: 2 },
        markLine: {
          symbol: "none",
          lineStyle: { type: "dashed", color: "#ef4444" },
          data: [{ yAxis: scoreThreshold, name: "报警阈值" }],
        },
      },
    ],
  };

  const rankingOption = {
    tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
    grid: { top: 12, left: 82, right: 20, bottom: 25 },
    xAxis: { type: "value", name: "标准化偏离", axisLabel: { fontSize: 10 } },
    yAxis: {
      type: "category",
      data: rankingSeries.map((item) => item.name),
      axisLabel: { fontSize: 10 },
    },
    series: [
      {
        type: "bar",
        data: rankingSeries.map((item) => ({
          value: item.value,
          itemStyle: { color: item.value < 0 ? "#ef4444" : "#f59e0b" },
        })),
        barWidth: 14,
      },
    ],
  };

  const columns: GridColDef[] = [
    {
      field: "Timestamp",
      headerName: "同刻日期",
      minWidth: 145,
      flex: 1,
      valueGetter: (_value, row) => formatDateTime(timestampForRow(row)),
    },
    {
      field: "Role",
      headerName: "角色",
      width: 90,
      valueFormatter: (value?: string) => (value === "target" ? "目标" : "参考"),
    },
    {
      field: "Score",
      headerName: "异常分数",
      width: 110,
      valueFormatter: (value?: number) =>
        typeof value === "number" ? value.toFixed(4) : "-",
    },
    {
      field: "IsBurst",
      headerName: "目标判定",
      width: 110,
      renderCell: ({ value, row }) =>
        row.Role === "target" || row.Day === result.day_count ? (
          <Chip
            size="small"
            label={value ? "爆管异常" : "正常"}
            color={value ? "error" : "success"}
            variant="outlined"
          />
        ) : (
          <Typography variant="caption" color="text.secondary">
            参考
          </Typography>
        ),
    },
  ];
  const tableRows = sortedRows.map((row) => ({ id: row.Day, ...row }));

  return (
    <Box className="h-full overflow-auto p-1">
      <Box className="mb-4 space-y-3">
        <Box
          className={`flex items-center gap-3 rounded-lg border px-4 py-3 ${
            isBurstDetected
              ? "border-red-100 bg-red-50 text-red-900"
              : "border-green-100 bg-green-50 text-green-900"
          }`}
        >
          {isBurstDetected ? <ErrorOutlineIcon /> : <CheckCircleIcon />}
          <Box className="flex-1">
            <Typography variant="subtitle2" className="font-bold">
              {isBurstDetected ? "目标时刻侦测到爆管异常" : "目标时刻未侦测到爆管异常"}
            </Typography>
            <Typography variant="caption" className="opacity-80">
              目标：{formatDateTime(result.target_time ?? result.summary.target_time)}；分数越低越异常
            </Typography>
          </Box>
        </Box>

        <Box className="flex items-center justify-between gap-2 px-1">
          <Typography variant="h6" className="min-w-0 flex-1 font-bold text-gray-900">
            爆管侦测结果
          </Typography>
          <Button
            size="small"
            variant="outlined"
            startIcon={<RoomIcon />}
            onClick={() =>
              void locateSensors(
                result.summary.latest_sensor_rankings
                  .slice(0, 5)
                  .map((item) => item.sensor_node),
              )
            }
            sx={{ flexShrink: 0, whiteSpace: "nowrap" }}
          >
            定位异常测点
          </Button>
        </Box>

        <Box className="grid grid-cols-2 gap-3">
          <MetricCard
            label="目标异常分数"
            value={targetRow ? targetRow.Score.toFixed(4) : "-"}
            hint={`报警阈值 ≤ ${scoreThreshold.toFixed(2)}`}
            tone={isBurstDetected ? "orange" : "green"}
          />
          <MetricCard
            label="目标异常排名"
            value={targetRank ? `${targetRank} / ${result.day_count}` : "-"}
            hint="在目标日与 14 个参考日中排序"
            tone="purple"
          />
          <MetricCard
            label="参考区间"
            value={`${formatDateTime(result.reference_window?.start)} ~ ${formatDateTime(result.reference_window?.end)}`}
            hint={`${result.reference_window?.day_count ?? 14} 个同刻参考日`}
            tone="blue"
          />
          <MetricCard
            label="有效 / 排除测点"
            value={`${result.sensor_nodes.length} / ${excludedCount}`}
            hint={`${result.sampling_interval_minutes ?? 15} 分钟采样，${result.points_per_day} 点/天`}
            tone="blue"
          />
        </Box>
      </Box>

      <Box className="mb-4 overflow-hidden rounded-xl border border-gray-100 bg-white shadow-sm">
        <Box className="flex items-center justify-between border-b border-gray-100 px-4 py-3">
          <Box className="flex items-center gap-2">
            <ShowChartIcon className="text-blue-600" />
            <Typography variant="subtitle1" className="font-bold">
              15 天同刻异常分数
            </Typography>
          </Box>
          <Tooltip title="灰色点为前 14 天参考，最后一个点为本次目标。">
            <InfoOutlinedIcon fontSize="small" className="text-gray-400" />
          </Tooltip>
        </Box>
        <Box sx={{ height: 270, px: 1.5, py: 1 }}>
          <ReactECharts
            option={chartOption}
            style={{ height: "100%", width: "100%" }}
            onEvents={{
              click: (params: { data?: { day?: number } }) =>
                setSelectedDay(params.data?.day ?? null),
            }}
          />
        </Box>
      </Box>

      {rankingSeries.length > 0 ? (
        <Box className="mb-4 overflow-hidden rounded-xl border border-gray-100 bg-white shadow-sm">
          <Box className="flex items-center justify-between border-b border-gray-100 px-4 py-3">
            <Typography variant="subtitle1" className="font-bold">
              目标测点压力偏离
            </Typography>
            <Typography variant="caption" color="text.secondary">
              负值越小，压降相对历史越明显
            </Typography>
          </Box>
          <Box sx={{ height: 280, px: 1.5, py: 1 }}>
            <ReactECharts option={rankingOption} style={{ height: "100%", width: "100%" }} />
          </Box>
        </Box>
      ) : null}

      <Box className="mb-4 overflow-hidden rounded-xl border border-gray-100 bg-white shadow-sm">
        <Box className="flex items-center gap-2 border-b border-gray-100 px-4 py-3">
          <FormatListBulleted className="text-blue-600" />
          <Typography variant="subtitle1" className="font-bold">
            同刻对照明细
          </Typography>
        </Box>
        <Box sx={{ height: 360, px: 1, py: 1 }}>
          <DataGrid
            rows={tableRows}
            columns={columns}
            localeText={zhCN.components.MuiDataGrid.defaultProps.localeText}
            pageSizeOptions={[15]}
            initialState={{ pagination: { paginationModel: { pageSize: 15, page: 0 } } }}
            disableRowSelectionOnClick
            onRowClick={(params) => setSelectedDay(Number(params.row.Day))}
            getRowClassName={(params) =>
              params.row.Day === resultsState.selectedDay ? "bg-blue-50" : ""
            }
            sx={{ border: "none" }}
          />
        </Box>
      </Box>
    </Box>
  );
};

export default DetectionResults;
