import { useEffect, useRef, useState, useCallback, memo } from 'react';
import L from 'leaflet';
import { useRiskStore } from '@/stores';
import { LodGridLayer } from '@/components/LodGridLayer';
import { GridStatsOverlay } from '@/components/GridStatsOverlay';
import { useLodGrid } from '@/hooks/useLodGrid';
import type { Alert, GridRisk } from '@/types';

export interface CellInfo {
  lat: number;
  lon: number;
  risk: number;
  nearestAlertId: string | null;
  nearestAlertDist: number;
}

interface AlertMapProps {
  selectedGridId: string | null;
  onGridClick: (id: string) => void;
  onCellInfo?: (info: CellInfo) => void;
  forecastDay?: 1 | 3 | 7;
  showAlertMarkers?: boolean;
  showGrid?: boolean;
  filteredAlerts?: Alert[];
  riskRange?: [number, number];
  isFullscreen?: boolean;
}

const WUHAN_CENTER: [number, number] = [30.59, 114.31];

const RISK_COLORS: [number, number, string][] = [
  [0.0, 0.2, '#22c55e'],
  [0.2, 0.4, '#3b82f6'],
  [0.4, 0.6, '#eab308'],
  [0.6, 0.8, '#f97316'],
  [0.8, 1.0, '#ef4444'],
];

function getRiskLabel(value: number): string {
  if (value >= 0.8) return '高风险';
  if (value >= 0.6) return '中高';
  if (value >= 0.4) return '中风险';
  if (value >= 0.2) return '中低';
  return '低风险';
}

const EMPTY_GRIDS: GridRisk[] = [];

function AlertMapComponent({
  selectedGridId,
  onGridClick,
  onCellInfo,
  forecastDay = 1,
  showAlertMarkers = true,
  showGrid = true,
  filteredAlerts = [],
  riskRange,
  isFullscreen = false,
}: AlertMapProps) {
  const mapRef = useRef<HTMLDivElement>(null);
  const mapInstanceRef = useRef<L.Map | null>(null);
  const alertLayerRef = useRef<L.LayerGroup | null>(null);
  const selectedMarkerRef = useRef<L.Rectangle | null>(null);
  const clickHandlerRef = useRef(onGridClick);
  const [currentZoom, setCurrentZoom] = useState(10);

  const grids = useRiskStore((s) => s.grids ?? EMPTY_GRIDS);

  // LOD grid data for stats overlay
  const { count, avgRisk, maxRisk, loading } = useLodGrid(currentZoom, forecastDay);

  useEffect(() => {
    clickHandlerRef.current = onGridClick;
  }, [onGridClick]);

  // Initialize map
  useEffect(() => {
    if (!mapRef.current || mapInstanceRef.current) return;

    const map = L.map(mapRef.current, {
      center: WUHAN_CENTER,
      zoom: 9,
      zoomControl: true,
      preferCanvas: true,
    });

    L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
      maxZoom: 19,
    }).addTo(map);

    map.on('zoomend', () => {
      setCurrentZoom(map.getZoom());
    });

    mapInstanceRef.current = map;

    return () => {
      map.remove();
      mapInstanceRef.current = null;
    };
  }, []);

  // Render alert markers overlay
  const renderAlertMarkers = useCallback(() => {
    const map = mapInstanceRef.current;
    if (!map) return;

    if (alertLayerRef.current) {
      try { map.removeLayer(alertLayerRef.current); } catch { /* ok */ }
      alertLayerRef.current = null;
    }

    if (!showAlertMarkers || !filteredAlerts || filteredAlerts.length === 0) return;

    const layer = L.layerGroup();
    const mapBounds = map.getBounds();
    const maxMarkers = 500;
    const step = Math.max(1, Math.floor(filteredAlerts.length / maxMarkers));

    for (let i = 0; i < filteredAlerts.length; i += step) {
      const alert = filteredAlerts[i];
      if (!alert.latitude || !alert.longitude) continue;

      // Skip if outside viewport
      if (
        alert.latitude < mapBounds.getSouth() ||
        alert.latitude > mapBounds.getNorth() ||
        alert.longitude < mapBounds.getWest() ||
        alert.longitude > mapBounds.getEast()
      ) {
        continue;
      }

      const isP1 = alert.priority === 'P1';

      const marker = L.circleMarker(
        [alert.latitude, alert.longitude],
        {
          radius: isP1 ? 6 : 4,
          fillColor: isP1 ? '#ef4444' : '#f97316',
          fillOpacity: 0.7,
          color: isP1 ? '#ef4444' : '#f97316',
          weight: 2,
          dashArray: isP1 ? undefined : '4 2',
        }
      );

      marker.bindTooltip(
        `<div style="font-size:12px;">
          <strong>${alert.priority}</strong> · ${(alert.risk_value * 100).toFixed(0)}%<br/>
          ${alert.region || ''} ${alert.street || ''}
        </div>`,
        { direction: 'top', offset: [0, -5] }
      );

      marker.on('click', () => {
        if (alert.grid_id) clickHandlerRef.current(alert.grid_id);
      });

      marker.addTo(layer);
    }

    layer.addTo(map);
    alertLayerRef.current = layer;
  }, [filteredAlerts, showAlertMarkers]);

  // Re-render alert markers when data changes
  useEffect(() => {
    renderAlertMarkers();
  }, [renderAlertMarkers]);

  // Also re-render on map zoom/pan
  useEffect(() => {
    const map = mapInstanceRef.current;
    if (!map) return;

    const handleMove = () => renderAlertMarkers();
    map.on('moveend', handleMove);
    return () => { map.off('moveend', handleMove); };
  }, [renderAlertMarkers]);

  // Selected grid highlight
  useEffect(() => {
    const map = mapInstanceRef.current;
    if (!map) return;

    if (selectedMarkerRef.current) {
      try { map.removeLayer(selectedMarkerRef.current); } catch { /* ok */ }
      selectedMarkerRef.current = null;
    }

    if (selectedGridId) {
      let grid = grids.find((g) => g.grid_id === selectedGridId);
      if (!grid) {
        const selectedAlertObj = filteredAlerts.find((a) => a.grid_id === selectedGridId);
        if (selectedAlertObj) {
          grid = grids.find((g) =>
            Math.abs(g.latitude - selectedAlertObj.latitude) < 0.001 &&
            Math.abs(g.longitude - selectedAlertObj.longitude) < 0.001
          );
        }
      }
      if (grid) {
        const latHalf = 0.00045;
        const lonHalf = 0.00052;
        const marker = L.rectangle(
          [
            [grid.latitude - latHalf, grid.longitude - lonHalf],
            [grid.latitude + latHalf, grid.longitude + lonHalf],
          ],
          {
            fillColor: '#3b82f6',
            fillOpacity: 0.3,
            color: '#3b82f6',
            weight: 3,
          }
        ).addTo(map);
        selectedMarkerRef.current = marker;

        map.flyTo([grid.latitude, grid.longitude], Math.max(map.getZoom(), 12), { duration: 0.5 });
      }
    }
  }, [selectedGridId, grids]);

  // Handle LOD grid cell click → find nearest alert
  const handleCellClick = useCallback(
    (lat: number, lon: number, risk: number) => {
      let nearestId: string | null = null;
      let minDist = Infinity;

      if (filteredAlerts) {
        for (const a of filteredAlerts) {
          const d = Math.sqrt((a.latitude - lat) ** 2 + (a.longitude - lon) ** 2);
          if (d < minDist) {
            minDist = d;
            nearestId = a.grid_id;
          }
        }
      }

      if (nearestId && minDist < 0.01) {
        clickHandlerRef.current(nearestId);
      } else if (onCellInfo) {
        onCellInfo({ lat, lon, risk, nearestAlertId: nearestId, nearestAlertDist: minDist });
      }
    },
    [filteredAlerts, onCellInfo]
  );

  // Invalidate Leaflet size after fullscreen toggle
  useEffect(() => {
    const map = mapInstanceRef.current;
    if (!map) return;
    const timer = setTimeout(() => map.invalidateSize({ animate: true }), 100);
    return () => clearTimeout(timer);
  }, [isFullscreen]);

  const containerHeight = isFullscreen ? 'calc(100vh - 120px)' : 'calc(100vh - 280px)';

  return (
    <div className="relative">
      <div ref={mapRef} className="w-full rounded-lg overflow-hidden" style={{ height: containerHeight }} />

      {/* LOD Grid Layer */}
      <LodGridLayer
        map={mapInstanceRef.current}
        forecastDay={forecastDay}
        visible={showGrid}
        riskRange={riskRange}
        onCellClick={handleCellClick}
      />

      {/* Stats overlay */}
      <GridStatsOverlay
        count={count}
        avgRisk={avgRisk}
        maxRisk={maxRisk}
        loading={loading}
        forecastDay={forecastDay}
      />

      {/* Legend */}
      <div className="absolute bottom-4 right-4 bg-bg-card/90 backdrop-blur rounded-lg border border-border-light shadow-sm z-[1000] px-4 py-3">
        <div className="text-[11px] font-semibold text-text-secondary mb-2">风险等级</div>
        <div className="space-y-1.5">
          {RISK_COLORS.slice().reverse().map(([min, max, color]) => (
            <div key={color} className="flex items-center gap-2">
              <div className="w-4 h-4 rounded" style={{ backgroundColor: color }} />
              <span className="text-[11px] text-text-secondary">
                {getRiskLabel((min + max) / 2)} ({(min * 100).toFixed(0)}-{(max * 100).toFixed(0)}%)
              </span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

export const AlertMap = memo(AlertMapComponent);
