import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
import { useMap } from '@vis.gl/react-maplibre';
import { PathLayer, ScatterplotLayer } from '@deck.gl/layers';
import { BaseMap } from '@common/components/map/BaseMap';
import { DeckGLOverlay } from '@common/components/map/DeckGLOverlay';
import type { ScatSegment } from './scatTypes';
import type { ApiZoneItem } from '../services/scatApi';
import { esiColor } from './scatConstants';
import { hexToRgba } from '@common/components/map/mapUtils';

interface ScatMapProps {
  segments: ScatSegment[];
  zones: ApiZoneItem[];
  selectedSeg: ScatSegment;
  jurisdictionFilter: string;
  onSelectSeg: (s: ScatSegment) => void;
  onOpenPopup: (idx: number) => void;
}

// ── FlyTo: 선택 구간·관할해경 변경 시 맵 이동 ──────────────
// 두 가지 트리거를 독립적으로 처리해 공통 FlyToController로 통합 불가
function ScatFlyToController({
  selectedSeg,
  zones,
}: {
  selectedSeg: ScatSegment;
  zones: ApiZoneItem[];
}) {
  const { current: map } = useMap();
  const prevIdRef = useRef<number | undefined>(undefined);
  const prevZonesLenRef = useRef<number>(0);

  // 선택 구간 변경 시 이동 (첫 렌더 제외)
  useEffect(() => {
    if (!map) return;
    if (prevIdRef.current !== undefined && prevIdRef.current !== selectedSeg.id) {
      map.flyTo({ center: [selectedSeg.lng, selectedSeg.lat], zoom: 12, duration: 600 });
    }
    prevIdRef.current = selectedSeg.id;
  }, [map, selectedSeg]);

  // 관할해경(zones) 변경 시 중심 이동
  useEffect(() => {
    if (!map || zones.length === 0) return;
    if (prevZonesLenRef.current === zones.length) return;
    prevZonesLenRef.current = zones.length;
    const validZones = zones.filter((z) => z.latCenter && z.lngCenter);
    if (validZones.length === 0) return;
    const avgLat = validZones.reduce((a, z) => a + z.latCenter, 0) / validZones.length;
    const avgLng = validZones.reduce((a, z) => a + z.lngCenter, 0) / validZones.length;
    map.flyTo({ center: [avgLng, avgLat], zoom: 9, duration: 800 });
  }, [map, zones]);

  return null;
}

// ── 줌 기반 스케일 계산 ─────────────────────────────────
function getZoomScale(zoom: number) {
  const zScale = Math.max(0, zoom - 9) / 5;
  return {
    polyWidth: 1 + zScale * 4,
    selPolyWidth: 2 + zScale * 5,
    glowWidth: 4 + zScale * 14,
    halfLenScale: 0.15 + zScale * 0.85,
    dotRadius: Math.round(4 + zScale * 10),
  };
}

// ── 세그먼트 폴리라인 좌표 생성 (lng, lat 순서) ──────────
function buildSegCoords(
  seg: ScatSegment,
  halfLenScale: number,
  segments: ScatSegment[],
): [number, number][] {
  const idx = segments.indexOf(seg);
  const prev = idx > 0 ? segments[idx - 1] : seg;
  const next = idx < segments.length - 1 ? segments[idx + 1] : seg;
  const dlat = next.lat - prev.lat;
  const dlng = next.lng - prev.lng;
  const dist = Math.sqrt(dlat * dlat + dlng * dlng);
  const nDlat = dist > 0 ? dlat / dist : 0;
  const nDlng = dist > 0 ? dlng / dist : 1;
  const halfLen = Math.min(seg.lengthM / 200000, 0.012) * halfLenScale;
  return [
    [seg.lng - nDlng * halfLen, seg.lat - nDlat * halfLen],
    [seg.lng, seg.lat],
    [seg.lng + nDlng * halfLen, seg.lat + nDlat * halfLen],
  ];
}

interface TooltipState {
  x: number;
  y: number;
  seg: ScatSegment;
}

// ── ScatMap ─────────────────────────────────────────────
function ScatMap({
  segments,
  zones,
  selectedSeg,
  jurisdictionFilter,
  onSelectSeg,
  onOpenPopup,
}: ScatMapProps) {
  const [zoom, setZoom] = useState(10);
  const [tooltip, setTooltip] = useState<TooltipState | null>(null);

  // zones 첫 렌더 기준으로 초기 중심 좌표 결정 (이후 불변)
  const [initialCenter] = useState<[number, number]>(() =>
    zones.length > 0
      ? [
          zones.reduce((a, z) => a + z.latCenter, 0) / zones.length,
          zones.reduce((a, z) => a + z.lngCenter, 0) / zones.length,
        ]
      : [33.38, 126.55],
  );

  const handleClick = useCallback(
    (seg: ScatSegment) => {
      onSelectSeg(seg);
      onOpenPopup(seg.id);
    },
    [onSelectSeg, onOpenPopup],
  );

  const zs = useMemo(() => getZoomScale(zoom), [zoom]);

  const glowLayer = useMemo(
    () =>
      new PathLayer({
        id: 'scat-glow',
        data: [selectedSeg],
        getPath: (d: ScatSegment) => buildSegCoords(d, zs.halfLenScale, segments),
        getColor: [34, 197, 94, 38],
        getWidth: zs.glowWidth,
        capRounded: true,
        jointRounded: true,
        widthMinPixels: 4,
        updateTriggers: {
          getPath: [zs.halfLenScale],
          getWidth: [zs.glowWidth],
        },
      }),
    [selectedSeg, segments, zs.glowWidth, zs.halfLenScale],
  );

  const segPathLayer = useMemo(
    () =>
      new PathLayer({
        id: 'scat-segments',
        data: segments,
        getPath: (d: ScatSegment) => buildSegCoords(d, zs.halfLenScale, segments),
        getColor: (d: ScatSegment) => {
          const isSelected = selectedSeg.id === d.id;
          const hexCol = isSelected ? '#22c55e' : esiColor(d.esiNum);
          return hexToRgba(hexCol, isSelected ? 242 : 178);
        },
        getWidth: (d: ScatSegment) => (selectedSeg.id === d.id ? zs.selPolyWidth : zs.polyWidth),
        capRounded: true,
        jointRounded: true,
        widthMinPixels: 2,
        pickable: true,
        onHover: (info: { object?: ScatSegment; x: number; y: number }) => {
          if (info.object) setTooltip({ x: info.x, y: info.y, seg: info.object });
          else setTooltip(null);
        },
        onClick: (info: { object?: ScatSegment }) => {
          if (info.object) handleClick(info.object);
        },
        updateTriggers: {
          getColor: [selectedSeg.id],
          getWidth: [selectedSeg.id, zs.selPolyWidth, zs.polyWidth],
          getPath: [zs.halfLenScale],
        },
      }),
    [segments, selectedSeg, zs, handleClick],
  );

  const shadowDotLayer = useMemo(
    () =>
      new ScatterplotLayer<ScatSegment>({
        id: 'scat-shadow-dots',
        data: segments,
        getPosition: (d) => [d.lng, d.lat],
        getRadius: zs.dotRadius + 2,
        getFillColor: [0, 0, 0, 70],
        stroked: false,
        radiusUnits: 'pixels',
        radiusMinPixels: 7,
        radiusMaxPixels: 18,
        pickable: false,
        updateTriggers: { getRadius: [zs.dotRadius] },
      }),
    [segments, zs.dotRadius],
  );

  const dotLayer = useMemo(
    () =>
      new ScatterplotLayer<ScatSegment>({
        id: 'scat-dots',
        data: segments,
        getPosition: (d) => [d.lng, d.lat],
        getRadius: zs.dotRadius,
        getFillColor: (d) => {
          if (d.status === '완료') return [34, 197, 94, 210];
          if (d.status === '진행중') return [234, 179, 8, 210];
          return [148, 163, 184, 200];
        },
        stroked: false,
        radiusUnits: 'pixels',
        radiusMinPixels: 5,
        radiusMaxPixels: 16,
        pickable: true,
        onHover: (info: { object?: ScatSegment; x: number; y: number }) => {
          if (info.object) setTooltip({ x: info.x, y: info.y, seg: info.object });
          else setTooltip(null);
        },
        onClick: (info: { object?: ScatSegment }) => {
          if (info.object) handleClick(info.object);
        },
        updateTriggers: { getRadius: [zs.dotRadius] },
      }),
    [segments, zs.dotRadius, handleClick],
  );

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const deckLayers: any[] = useMemo(
    () => [glowLayer, segPathLayer, shadowDotLayer, dotLayer],
    [glowLayer, segPathLayer, shadowDotLayer, dotLayer],
  );

  const totalLen = segments.reduce((a, s) => a + s.lengthM, 0);
  const doneLen = segments.filter((s) => s.status === '완료').reduce((a, s) => a + s.lengthM, 0);
  const highSens = segments
    .filter((s) => s.sensitivity === '최상' || s.sensitivity === '상')
    .reduce((a, s) => a + s.lengthM, 0);

  return (
    <div className="absolute inset-0 overflow-hidden">
      <BaseMap center={initialCenter} zoom={10} onZoom={setZoom}>
        <DeckGLOverlay layers={deckLayers} />
        <ScatFlyToController selectedSeg={selectedSeg} zones={zones} />
      </BaseMap>

      {/* 호버 툴팁 */}
      {tooltip && (
        <div
          className="pointer-events-none text-fg rounded-[6px] px-2 py-1 font-korean text-label-2"
          style={{
            position: 'absolute',
            left: tooltip.x + 12,
            top: tooltip.y - 48,
            background: 'color-mix(in srgb, var(--bg-base) 92%, transparent)',
            border: '1px solid var(--stroke-default)',
            boxShadow: '0 4px 12px rgba(0,0,0,0.4)',
            zIndex: 1000,
            whiteSpace: 'nowrap',
          }}
        >
          <div className="font-bold font-korean">{tooltip.seg.name}</div>
          <div className="text-caption opacity-70">
            {tooltip.seg.code} · ESI {tooltip.seg.esi} ·{' '}
            {tooltip.seg.status === '완료' ? '✓' : tooltip.seg.status === '진행중' ? '⏳' : '—'}{' '}
            {tooltip.seg.status}
          </div>
        </div>
      )}

      {/* Status chips */}
      <div className="absolute top-3.5 left-3.5 flex gap-2 z-[1000]">
        <div className="flex items-center gap-1.5 px-3 py-1.5 bg-[color-mix(in_srgb,var(--bg-base)_92%,transparent)] backdrop-blur-xl border border-stroke rounded-full text-label-2 text-fg-sub font-korean">
          <span className="w-1.5 h-1.5 rounded-full bg-color-accent shadow-[0_0_6px_var(--color-accent)]" />
          Pre-SCAT 사전조사
        </div>
        <div className="flex items-center gap-1.5 px-3 py-1.5 bg-[color-mix(in_srgb,var(--bg-base)_92%,transparent)] backdrop-blur-xl border border-stroke rounded-full text-label-2 text-fg-sub font-korean">
          {jurisdictionFilter || '전체'} 관할 해안 · {segments.length}개 구간
        </div>
      </div>

      {/* Right info cards */}
      <div className="absolute top-3.5 right-8 w-[260px] flex flex-col gap-2 z-[1000] max-h-[calc(100%-100px)] overflow-y-auto scrollbar-thin">
        {/* ESI Legend */}
        <div className="bg-[color-mix(in_srgb,var(--bg-base)_92%,transparent)] backdrop-blur-xl border border-stroke rounded-md p-3.5 shadow-[0_4px_20px_rgba(0,0,0,0.3)]">
          <div className="text-caption font-bold uppercase tracking-wider text-fg-disabled mb-2.5">
            ESI 민감도 분류 범례
          </div>
          {[
            { esi: 'ESI 10', label: '갯벌·습지·맹그로브', color: '#991b1b' },
            { esi: 'ESI 9', label: '쉘터 갯벌', color: '#b91c1c' },
            { esi: 'ESI 8', label: '쉘터 암반 해안', color: '#dc2626' },
            { esi: 'ESI 7', label: '노출 갯벌', color: '#ef4444' },
            { esi: 'ESI 6', label: '자갈·혼합 해안', color: '#f97316' },
            { esi: 'ESI 5', label: '혼합 모래/자갈', color: '#fb923c' },
            { esi: 'ESI 3-4', label: '모래 해안', color: '#facc15' },
            { esi: 'ESI 1-2', label: '암반·인공 구조물', color: '#4ade80' },
          ].map((item, i) => (
            <div key={i} className="flex items-center gap-2 py-1 text-label-2">
              <span
                className="w-3.5 h-1.5 rounded-sm flex-shrink-0"
                style={{ background: item.color }}
              />
              <span className="text-fg-sub font-korean">{item.label}</span>
              <span className="ml-auto font-mono text-caption text-fg">{item.esi}</span>
            </div>
          ))}
        </div>

        {/* Progress */}
        <div className="bg-[color-mix(in_srgb,var(--bg-base)_92%,transparent)] backdrop-blur-xl border border-stroke rounded-md p-3.5 shadow-[0_4px_20px_rgba(0,0,0,0.3)]">
          <div className="text-caption font-bold uppercase tracking-wider text-fg-disabled mb-2.5">
            조사 정보
          </div>
          <div className="mt-2.5">
            {[
              ['총 해안선', `${(totalLen / 1000).toFixed(1)} km`, ''],
              ['조사 완료', `${(doneLen / 1000).toFixed(1)} km`, 'var(--color-success)'],
              ['고민감 구간', `${(highSens / 1000).toFixed(1)} km`, 'var(--color-danger)'],
              [
                '방제 우선 구간',
                `${segments.filter((s) => s.sensitivity === '최상').length}개`,
                'var(--color-warning)',
              ],
            ].map(([label, val, color], i) => (
              <div
                key={i}
                className="flex justify-between py-1.5 border-b border-stroke last:border-b-0 text-label-2"
              >
                <span className="text-fg-sub font-korean">{label}</span>
                <span
                  className="font-mono font-medium text-label-2"
                  style={{ color: color || undefined }}
                >
                  {val}
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

export default ScatMap;
