import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import { useMap } from 'react-map-gl/maplibre';
import type { MapLayerMouseEvent } from 'maplibre-gl';
import type { Ship, VesselAnalysisDto } from '../../types';
import { fetchFleetCompanies, fetchGroupHistory, fetchGroupCorrelations, fetchCorrelationTracks } from '../../services/vesselAnalysis';
import type { FleetCompany, GearCorrelationItem, CorrelationVesselTrack } from '../../services/vesselAnalysis';
import type { UseGroupPolygonsResult } from '../../hooks/useGroupPolygons';
import { useGearReplayStore } from '../../stores/gearReplayStore';

// ── 분리된 모듈 ──
import type { PickerCandidate, HoverTooltipState, GearPickerPopupState } from './fleetClusterTypes';
import { EMPTY_ANALYSIS } from './fleetClusterTypes';
import { fillGapFrames } from './fleetClusterUtils';
import { useFleetClusterGeoJson } from './useFleetClusterGeoJson';
import FleetClusterMapLayers from './FleetClusterMapLayers';
import CorrelationPanel from './CorrelationPanel';
import HistoryReplayController from './HistoryReplayController';
import FleetGearListPanel from './FleetGearListPanel';

// ── re-export (KoreaMap 호환) ──
export type { SelectedGearGroupData, SelectedFleetData } from './fleetClusterTypes';

interface Props {
  ships: Ship[];
  analysisMap?: Map<string, VesselAnalysisDto>;
  clusters?: Map<number, string[]>;
  onShipSelect?: (mmsi: string) => void;
  onFleetZoom?: (bounds: { minLat: number; maxLat: number; minLng: number; maxLng: number }) => void;
  onSelectedGearChange?: (data: import('./fleetClusterTypes').SelectedGearGroupData | null) => void;
  onSelectedFleetChange?: (data: import('./fleetClusterTypes').SelectedFleetData | null) => void;
  groupPolygons?: UseGroupPolygonsResult;
}

export function FleetClusterLayer({ ships, analysisMap: analysisMapProp, onShipSelect, onFleetZoom, onSelectedGearChange, onSelectedFleetChange, groupPolygons }: Props) {
  const analysisMap = analysisMapProp ?? EMPTY_ANALYSIS;

  // ── 선단/어구 패널 상태 ──
  const [companies, setCompanies] = useState<Map<number, FleetCompany>>(new Map());
  const [expandedFleet, setExpandedFleet] = useState<number | null>(null);
  const [activeSection, setActiveSection] = useState<string | null>('fleet');
  const toggleSection = (key: string) => setActiveSection(prev => prev === key ? null : key);
  const [hoveredFleetId, setHoveredFleetId] = useState<number | null>(null);
  const [expandedGearGroup, setExpandedGearGroup] = useState<string | null>(null);
  const [selectedGearGroup, setSelectedGearGroup] = useState<string | null>(null);

  // ── 맵 팝업/툴팁 상태 ──
  const [hoverTooltip, setHoverTooltip] = useState<HoverTooltipState | null>(null);
  const [gearPickerPopup, setGearPickerPopup] = useState<GearPickerPopupState | null>(null);
  const [pickerHoveredGroup, setPickerHoveredGroup] = useState<string | null>(null);

  // ── 연관성 데이터 ──
  const [correlationData, setCorrelationData] = useState<GearCorrelationItem[]>([]);
  const [correlationLoading, setCorrelationLoading] = useState(false);
  const [correlationTracks, setCorrelationTracks] = useState<CorrelationVesselTrack[]>([]);
  const [enabledVessels, setEnabledVessels] = useState<Set<string>>(new Set());
  const [enabledModels, setEnabledModels] = useState<Set<string>>(new Set(['identity', 'default', 'aggressive', 'conservative', 'proximity-heavy', 'visit-pattern']));
  const [hoveredTarget, setHoveredTarget] = useState<{ mmsi: string; model: string } | null>(null);

  // ── Zustand store (히스토리 재생) ──
  const historyActive = useGearReplayStore(s => s.historyFrames.length > 0);

  // ── 맵 + ref ──
  const { current: mapRef } = useMap();
  const registeredRef = useRef(false);
  const dataRef = useRef<{ shipMap: Map<string, Ship>; groupPolygons: UseGroupPolygonsResult | undefined; onFleetZoom: Props['onFleetZoom'] }>({ shipMap: new Map(), groupPolygons, onFleetZoom });

  // ── 초기 로드 ──
  useEffect(() => {
    fetchFleetCompanies().then(setCompanies).catch(() => {});
  }, []);

  // ── 히스토리 로드 (3개 API 순차 await → 스토어 초기화 → 재생) ──
  const loadHistory = async (groupKey: string) => {
    // 1. 모든 데이터를 병렬 fetch
    const [history, corrRes, trackRes] = await Promise.all([
      fetchGroupHistory(groupKey, 12),
      fetchGroupCorrelations(groupKey, 0.3).catch(() => ({ items: [] as GearCorrelationItem[] })),
      fetchCorrelationTracks(groupKey, 24, 0.3).catch(() => ({ vessels: [] as CorrelationVesselTrack[] })),
    ]);

    // 2. 데이터 전처리
    const sorted = history.reverse();
    const filled = fillGapFrames(sorted);
    const corrData = corrRes.items;
    const corrTracks = trackRes.vessels;

    // 디버그: fetch 결과 확인
    const withTrack = corrTracks.filter(v => v.track && v.track.length > 0).length;
    console.log('[loadHistory] fetch 완료:', {
      history: history.length,
      corrData: corrData.length,
      corrTracks: corrTracks.length,
      withTrack,
      sampleTrack: corrTracks[0] ? { mmsi: corrTracks[0].mmsi, trackPts: corrTracks[0].track?.length, score: corrTracks[0].score } : 'none',
    });

    const vessels = new Set(corrTracks.filter(v => v.score >= 0.7).map(v => v.mmsi));

    // 3. React 상태 동기화 (패널 표시용)
    setCorrelationData(corrData);
    setCorrelationTracks(corrTracks);
    setEnabledVessels(vessels);
    setCorrelationLoading(false);

    // 4. 스토어 초기화 (모든 데이터 포함) → 재생 시작
    const store = useGearReplayStore.getState();
    store.loadHistory(filled, corrTracks, corrData, enabledModels, vessels);
    store.play();
  };

  const closeHistory = useCallback(() => {
    useGearReplayStore.getState().reset();
    setSelectedGearGroup(null);
  }, []);

  // ── enabledModels/enabledVessels/hoveredTarget → store 동기화 ──
  useEffect(() => {
    useGearReplayStore.getState().setEnabledModels(enabledModels);
  }, [enabledModels]);

  useEffect(() => {
    useGearReplayStore.getState().setEnabledVessels(enabledVessels);
  }, [enabledVessels]);

  useEffect(() => {
    useGearReplayStore.getState().setHoveredMmsi(hoveredTarget?.mmsi ?? null);
  }, [hoveredTarget]);

  // ── ESC 키 ──
  useEffect(() => {
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        if (historyActive) closeHistory();
        setSelectedGearGroup(null);
        setExpandedFleet(null);
        setExpandedGearGroup(null);
      }
    };
    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, [historyActive, closeHistory]);

  // ── 맵 이벤트 등록 ──
  useEffect(() => {
    const map = mapRef?.getMap();
    if (!map || registeredRef.current) return;

    const fleetLayers = ['fleet-cluster-fill-layer'];
    const gearLayers = ['gear-cluster-fill-layer'];
    const allLayers = [...fleetLayers, ...gearLayers];
    const setCursor = (cursor: string) => { map.getCanvas().style.cursor = cursor; };

    const onFleetEnter = (e: MapLayerMouseEvent) => {
      setCursor('pointer');
      const feat = e.features?.[0];
      if (!feat) return;
      const cid = feat.properties?.clusterId as number | undefined;
      if (cid != null) {
        setHoveredFleetId(cid);
        setHoverTooltip({ lng: e.lngLat.lng, lat: e.lngLat.lat, type: 'fleet', id: cid });
      }
    };
    const onFleetLeave = () => {
      setCursor('');
      setHoveredFleetId(null);
      setHoverTooltip(prev => prev?.type === 'fleet' ? null : prev);
    };

    const handleFleetSelect = (cid: number) => {
      const d = dataRef.current;
      setExpandedFleet(prev => prev === cid ? null : cid);
      setActiveSection('fleet');
      const group = d.groupPolygons?.fleetGroups.find(g => Number(g.groupKey) === cid);
      if (!group || group.members.length === 0) return;
      let minLat = Infinity, maxLat = -Infinity, minLng = Infinity, maxLng = -Infinity;
      for (const m of group.members) {
        if (m.lat < minLat) minLat = m.lat;
        if (m.lat > maxLat) maxLat = m.lat;
        if (m.lon < minLng) minLng = m.lon;
        if (m.lon > maxLng) maxLng = m.lon;
      }
      if (minLat !== Infinity) d.onFleetZoom?.({ minLat, maxLat, minLng, maxLng });
      loadHistory(String(cid));
    };

    const handleGearGroupZoomFromMap = (name: string) => {
      const d = dataRef.current;
      setSelectedGearGroup(prev => prev === name ? null : name);
      setExpandedGearGroup(name);
      const isInZone = d.groupPolygons?.gearInZoneGroups.some(g => g.groupKey === name);
      setActiveSection(isInZone ? 'inZone' : 'outZone');
      requestAnimationFrame(() => {
        setTimeout(() => {
          document.getElementById(`gear-row-${name}`)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
        }, 50);
      });
      const allGroups = d.groupPolygons ? [...d.groupPolygons.gearInZoneGroups, ...d.groupPolygons.gearOutZoneGroups] : [];
      const group = allGroups.find(g => g.groupKey === name);
      if (!group || group.members.length === 0) return;
      let minLat = Infinity, maxLat = -Infinity, minLng = Infinity, maxLng = -Infinity;
      for (const m of group.members) {
        if (m.lat < minLat) minLat = m.lat;
        if (m.lat > maxLat) maxLat = m.lat;
        if (m.lon < minLng) minLng = m.lon;
        if (m.lon > maxLng) maxLng = m.lon;
      }
      if (minLat !== Infinity) d.onFleetZoom?.({ minLat, maxLat, minLng, maxLng });
      loadHistory(name);
    };

    const onPolygonClick = (e: MapLayerMouseEvent) => {
      const features = map.queryRenderedFeatures(e.point, { layers: allLayers });
      if (features.length === 0) return;
      const seen = new Set<string>();
      const candidates: PickerCandidate[] = [];
      for (const f of features) {
        const cid = f.properties?.clusterId as number | undefined;
        const gearName = f.properties?.name as string | undefined;
        if (cid != null) {
          const key = `fleet-${cid}`;
          if (seen.has(key)) continue;
          seen.add(key);
          const d = dataRef.current;
          const g = d.groupPolygons?.fleetGroups.find(x => Number(x.groupKey) === cid);
          candidates.push({ name: g?.groupLabel ?? `선단 #${cid}`, count: g?.memberCount ?? 0, inZone: false, isFleet: true, clusterId: cid });
        } else if (gearName) {
          if (seen.has(gearName)) continue;
          seen.add(gearName);
          candidates.push({ name: gearName, count: f.properties?.gearCount ?? 0, inZone: f.properties?.inZone === 1, isFleet: false });
        }
      }
      if (candidates.length === 1) {
        const c = candidates[0];
        if (c.isFleet && c.clusterId != null) handleFleetSelect(c.clusterId);
        else handleGearGroupZoomFromMap(c.name);
      } else if (candidates.length > 1) {
        setGearPickerPopup({ lng: e.lngLat.lng, lat: e.lngLat.lat, candidates });
      }
    };

    const onGearEnter = (e: MapLayerMouseEvent) => {
      setCursor('pointer');
      const feat = e.features?.[0];
      if (!feat) return;
      const name = feat.properties?.name as string | undefined;
      if (name) setHoverTooltip({ lng: e.lngLat.lng, lat: e.lngLat.lat, type: 'gear', id: name });
    };
    const onGearLeave = () => {
      setCursor('');
      setHoverTooltip(prev => prev?.type === 'gear' ? null : prev);
    };

    const register = () => {
      const ready = allLayers.every(id => map.getLayer(id));
      if (!ready) return;
      registeredRef.current = true;
      for (const id of fleetLayers) {
        map.on('mouseenter', id, onFleetEnter);
        map.on('mouseleave', id, onFleetLeave);
        map.on('click', id, onPolygonClick);
      }
      for (const id of gearLayers) {
        map.on('mouseenter', id, onGearEnter);
        map.on('mouseleave', id, onGearLeave);
        map.on('click', id, onPolygonClick);
      }
    };

    register();
    if (!registeredRef.current) {
      const interval = setInterval(() => {
        register();
        if (registeredRef.current) clearInterval(interval);
      }, 500);
      return () => clearInterval(interval);
    }
  }, [mapRef]);

  // ── ships map ──
  const shipMap = useMemo(() => {
    const m = new Map<string, Ship>();
    for (const s of ships) m.set(s.mmsi, s);
    return m;
  }, [ships]);

  dataRef.current = { shipMap, groupPolygons, onFleetZoom };

  // ── 부모 콜백 동기화: 어구 그룹 선택 ──
  useEffect(() => {
    if (!selectedGearGroup || historyActive) {
      onSelectedGearChange?.(null);
      if (historyActive) return;
      return;
    }
    const allGroups = groupPolygons ? [...groupPolygons.gearInZoneGroups, ...groupPolygons.gearOutZoneGroups] : [];
    const group = allGroups.find(g => g.groupKey === selectedGearGroup);
    if (!group) { onSelectedGearChange?.(null); return; }
    const parent = group.members.find(m => m.isParent);
    const gears = group.members.filter(m => !m.isParent);
    const toShip = (m: typeof group.members[0]): Ship => ({
      mmsi: m.mmsi, name: m.name, lat: m.lat, lng: m.lon,
      heading: m.cog, speed: m.sog, course: m.cog,
      category: 'fishing', lastSeen: Date.now(),
    });
    onSelectedGearChange?.({ parent: parent ? toShip(parent) : null, gears: gears.map(toShip), groupName: selectedGearGroup });
  }, [selectedGearGroup, groupPolygons, onSelectedGearChange, historyActive]);

  // ── 연관성 데이터 로드 (loadHistory에서 일괄 처리, 여기서는 비재생 모드만) ──
  useEffect(() => {
    if (!selectedGearGroup || historyActive) { if (!selectedGearGroup) { setCorrelationData([]); } return; }
    let cancelled = false;
    setCorrelationLoading(true);
    fetchGroupCorrelations(selectedGearGroup, 0.3)
      .then(res => { if (!cancelled) setCorrelationData(res.items); })
      .catch(() => { if (!cancelled) setCorrelationData([]); })
      .finally(() => { if (!cancelled) setCorrelationLoading(false); });
    return () => { cancelled = true; };
  }, [selectedGearGroup, historyActive]);

  // ── 연관 선박 항적 로드 (loadHistory에서 일괄 처리, 여기서는 비재생 모드만) ──
  useEffect(() => {
    if (!selectedGearGroup || historyActive) { if (!selectedGearGroup) { setCorrelationTracks([]); setEnabledVessels(new Set()); } return; }
    let cancelled = false;
    fetchCorrelationTracks(selectedGearGroup, 24, 0.3)
      .then(res => {
        if (!cancelled) {
          setCorrelationTracks(res.vessels);
          setEnabledVessels(new Set(res.vessels.filter(v => v.score >= 0.7).map(v => v.mmsi)));
        }
      })
      .catch(() => { if (!cancelled) setCorrelationTracks([]); });
    return () => { cancelled = true; };
  }, [selectedGearGroup, historyActive]);

  // ── 부모 콜백 동기화: 선단 선택 ──
  useEffect(() => {
    if (expandedFleet === null || historyActive) {
      onSelectedFleetChange?.(null);
      if (historyActive) return;
      return;
    }
    const group = groupPolygons?.fleetGroups.find(g => Number(g.groupKey) === expandedFleet);
    const company = companies.get(expandedFleet);
    if (!group) { onSelectedFleetChange?.(null); return; }
    const fleetShips: Ship[] = group.members.map(m => ({
      mmsi: m.mmsi, name: m.name, lat: m.lat, lng: m.lon,
      heading: m.cog, speed: m.sog, course: m.cog,
      category: 'fishing', lastSeen: Date.now(),
    }));
    onSelectedFleetChange?.({ clusterId: expandedFleet, ships: fleetShips, companyName: company?.nameCn || group.groupLabel || `선단 #${expandedFleet}` });
  }, [expandedFleet, groupPolygons, companies, onSelectedFleetChange, historyActive]);

  // ── GeoJSON 훅 ──
  const hoveredMmsi = hoveredTarget?.mmsi ?? null;
  const geo = useFleetClusterGeoJson({
    ships, shipMap, groupPolygons, analysisMap,
    hoveredFleetId, selectedGearGroup, pickerHoveredGroup,
    historyActive,
    correlationData, correlationTracks,
    enabledModels, enabledVessels, hoveredMmsi,
  });

  // ── 어구 그룹 데이터 ──
  const inZoneGearGroups = groupPolygons?.gearInZoneGroups ?? [];
  const outZoneGearGroups = groupPolygons?.gearOutZoneGroups ?? [];

  // ── 핸들러 ──
  const handleFleetZoom = useCallback((clusterId: number) => {
    const group = groupPolygons?.fleetGroups.find(g => Number(g.groupKey) === clusterId);
    if (!group || group.members.length === 0) return;
    let minLat = Infinity, maxLat = -Infinity, minLng = Infinity, maxLng = -Infinity;
    for (const m of group.members) {
      if (m.lat < minLat) minLat = m.lat;
      if (m.lat > maxLat) maxLat = m.lat;
      if (m.lon < minLng) minLng = m.lon;
      if (m.lon > maxLng) maxLng = m.lon;
    }
    if (minLat === Infinity) return;
    onFleetZoom?.({ minLat, maxLat, minLng, maxLng });
  }, [groupPolygons?.fleetGroups, onFleetZoom]);

  const handleGearGroupZoom = useCallback((parentName: string) => {
    setSelectedGearGroup(prev => prev === parentName ? null : parentName);
    setExpandedGearGroup(parentName);
    const isInZone = groupPolygons?.gearInZoneGroups.some(g => g.groupKey === parentName);
    setActiveSection(isInZone ? 'inZone' : 'outZone');
    requestAnimationFrame(() => {
      setTimeout(() => {
        document.getElementById(`gear-row-${parentName}`)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }, 50);
    });
    const allGroups = groupPolygons ? [...groupPolygons.gearInZoneGroups, ...groupPolygons.gearOutZoneGroups] : [];
    const group = allGroups.find(g => g.groupKey === parentName);
    if (!group || group.members.length === 0) return;
    let minLat = Infinity, maxLat = -Infinity, minLng = Infinity, maxLng = -Infinity;
    for (const m of group.members) {
      if (m.lat < minLat) minLat = m.lat;
      if (m.lat > maxLat) maxLat = m.lat;
      if (m.lon < minLng) minLng = m.lon;
      if (m.lon > maxLng) maxLng = m.lon;
    }
    if (minLat === Infinity) return;
    onFleetZoom?.({ minLat, maxLat, minLng, maxLng });
    loadHistory(parentName);
  }, [groupPolygons, onFleetZoom]);

  // ── Picker 콜백 ──
  const handlePickerSelect = useCallback((c: PickerCandidate) => {
    if (c.isFleet && c.clusterId != null) {
      setExpandedFleet(prev => prev === c.clusterId! ? null : c.clusterId!);
      setActiveSection('fleet');
      handleFleetZoom(c.clusterId);
    } else {
      handleGearGroupZoom(c.name);
    }
    setGearPickerPopup(null);
    setPickerHoveredGroup(null);
  }, [handleFleetZoom, handleGearGroupZoom]);

  // ── CorrelationPanel용 멤버 수 ──
  const selectedGroupMemberCount = useMemo(() => {
    if (!selectedGearGroup || !groupPolygons) return 0;
    const allGroups = [...groupPolygons.gearInZoneGroups, ...groupPolygons.gearOutZoneGroups];
    return allGroups.find(g => g.groupKey === selectedGearGroup)?.memberCount ?? 0;
  }, [selectedGearGroup, groupPolygons]);

  return (
    <>
      {/* ── 맵 레이어 ── */}
      <FleetClusterMapLayers
        geo={geo}
        selectedGearGroup={selectedGearGroup}
        hoveredMmsi={hoveredMmsi}
        enabledModels={enabledModels}
        expandedFleet={expandedFleet}
        historyActive={historyActive}
        hoverTooltip={hoverTooltip}
        gearPickerPopup={gearPickerPopup}
        pickerHoveredGroup={pickerHoveredGroup}
        groupPolygons={groupPolygons}
        companies={companies}
        analysisMap={analysisMap}
        hasCorrelationTracks={correlationTracks.length > 0}
        onPickerHover={setPickerHoveredGroup}
        onPickerSelect={handlePickerSelect}
        onPickerClose={() => { setGearPickerPopup(null); setPickerHoveredGroup(null); }}
      />

      {/* ── 연관성 패널 ── */}
      {selectedGearGroup && (
        <CorrelationPanel
          selectedGearGroup={selectedGearGroup}
          memberCount={selectedGroupMemberCount}
          groupPolygons={groupPolygons}
          correlationByModel={geo.correlationByModel}
          availableModels={geo.availableModels}
          enabledModels={enabledModels}
          enabledVessels={enabledVessels}
          correlationLoading={correlationLoading}
          hoveredTarget={hoveredTarget}
          onEnabledModelsChange={(updater) => setEnabledModels(updater)}
          onEnabledVesselsChange={(updater) => setEnabledVessels(updater)}
          onHoveredTargetChange={setHoveredTarget}
        />
      )}

      {/* ── 재생 컨트롤러 ── */}
      {historyActive && (
        <HistoryReplayController
          onClose={closeHistory}
          onFilterByScore={(minPct) => {
            // 전역: 모든 모델의 모든 대상에 적용 (모델 on/off 무관)
            if (minPct === null) {
              setEnabledVessels(new Set(correlationTracks.map(v => v.mmsi)));
            } else {
              const threshold = minPct / 100;
              const filtered = new Set<string>();
              // correlationData에서 모든 모델의 모든 대상 중 최고 score 기준
              const maxScores = new Map<string, number>();
              for (const c of correlationData) {
                const prev = maxScores.get(c.targetMmsi) ?? 0;
                if (c.score > prev) maxScores.set(c.targetMmsi, c.score);
              }
              for (const [mmsi, score] of maxScores) {
                if (score >= threshold) filtered.add(mmsi);
              }
              setEnabledVessels(filtered);
            }
          }}
        />
      )}

      {/* ── 좌측 목록 패널 ── */}
      <FleetGearListPanel
        fleetList={geo.fleetList}
        companies={companies}
        analysisMap={analysisMap}
        inZoneGearGroups={inZoneGearGroups}
        outZoneGearGroups={outZoneGearGroups}
        activeSection={activeSection}
        expandedFleet={expandedFleet}
        expandedGearGroup={expandedGearGroup}
        hoveredFleetId={hoveredFleetId}
        onToggleSection={toggleSection}
        onExpandFleet={setExpandedFleet}
        onHoverFleet={setHoveredFleetId}
        onFleetZoom={handleFleetZoom}
        onGearGroupZoom={handleGearGroupZoom}
        onExpandGearGroup={setExpandedGearGroup}
        onShipSelect={(mmsi) => onShipSelect?.(mmsi)}
      />
    </>
  );
}
