import { useState, useRef, useEffect } from 'react';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import {
  fetchSensitiveResourcesGeojson,
  fetchPredictionParticlesGeojson,
} from '@components/prediction/services/predictionApi';
import type { OilSpillReportData } from '@interfaces/reports/ReportsInterface';
import {
  S,
  parseCoord,
  haversineKm,
  getGeomCentroid,
  CATEGORY_COLORS,
  getCategoryColor,
} from '../OilSpillReportTemplate';

export function SensitiveResourceMapSection({
  data,
  editing,
  onChange,
}: {
  data: OilSpillReportData;
  editing: boolean;
  onChange: (d: OilSpillReportData) => void;
}) {
  const mapContainerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<maplibregl.Map | null>(null);
  const [mapVisible, setMapVisible] = useState(false);
  const [loading, setLoading] = useState(false);
  const [capturing, setCapturing] = useState(false);
  const [legendLabels, setLegendLabels] = useState<string[]>([]);
  const acdntSn = data.acdntSn;

  const RELEVANT_KEYWORDS = [
    '양식',
    '어장',
    '해수욕',
    '수산시장',
    '어시장',
    '갯벌',
    '서식지',
    '보호종',
    '생물',
    '조류',
    '포유',
    '파충',
  ];

  const handleLoad = async () => {
    if (!acdntSn) return;
    setLoading(true);
    try {
      const [geojson, particlesGeojson] = await Promise.all([
        fetchSensitiveResourcesGeojson(acdntSn),
        fetchPredictionParticlesGeojson(acdntSn),
      ]);
      // 관련 카테고리만 필터링 + 카테고리별 색상 추가
      const filteredGeojson = {
        ...geojson,
        features: geojson.features
          .filter((f) => {
            const cat = (f.properties as { category?: string })?.category ?? '';
            return RELEVANT_KEYWORDS.some((kw) => cat.includes(kw));
          })
          .map((f) => ({
            ...f,
            properties: {
              ...f.properties,
              _color: getCategoryColor((f.properties as { category?: string })?.category ?? ''),
            },
          })),
      };
      // 실제 존재하는 카테고리 라벨만 범례에 표시
      const presentColors = new Set(
        filteredGeojson.features.map((f) => (f.properties as { _color: string })._color),
      );
      setLegendLabels(
        CATEGORY_COLORS.filter((c) => presentColors.has(c.color)).map((c) => c.label),
      );
      // 민감자원 GeoJSON → 6개 섹션 자동 채우기
      const HABITAT_TYPES = [
        '갯벌',
        '해조류서식지',
        '바다목장',
        '바다숲',
        '산호류서식지',
        '인공어초',
        '해초류서식지',
      ];
      const incLat = parseCoord(data.incident.lat);
      const incLon = parseCoord(data.incident.lon);
      const calcDist = (geom: { type: string; coordinates: unknown }) => {
        if (incLat == null || incLon == null) return '';
        const centroid = getGeomCentroid(geom);
        return centroid ? haversineKm(incLat, incLon, centroid[1], centroid[0]).toFixed(2) : '';
      };

      // aquaculture (어장)
      const aquacultureRows = geojson.features
        .filter((f) => ((f.properties as { category?: string })?.category ?? '').includes('어장'))
        .sort((a, b) => {
          const aNo = String((a.properties as Record<string, unknown>)['lcns_no'] ?? '');
          const bNo = String((b.properties as Record<string, unknown>)['lcns_no'] ?? '');
          return aNo.localeCompare(bNo, 'ko', { numeric: true });
        })
        .map((f) => {
          const p = f.properties as Record<string, unknown>;
          const lcnsNo = String(p['lcns_no'] ?? '');
          const fidsKnd = String(p['fids_knd'] ?? '');
          const farmKnd = String(p['farm_knd'] ?? '');
          const parts = [lcnsNo, fidsKnd, farmKnd].filter(Boolean);
          return {
            type: parts.join('_'),
            area: p['area'] != null ? Number(p['area']).toFixed(2) : '',
            distance: calcDist(f.geometry as { type: string; coordinates: unknown }),
          };
        });

      // beaches (해수욕장)
      const beachRows = geojson.features
        .filter((f) => ((f.properties as { category?: string })?.category ?? '').includes('해수욕'))
        .map((f) => {
          const p = f.properties as Record<string, unknown>;
          return {
            name: String(p['beach_nm'] ?? p['name'] ?? p['nm'] ?? ''),
            distance: calcDist(f.geometry as { type: string; coordinates: unknown }),
          };
        });

      // markets (수산시장·어시장)
      const marketRows = geojson.features
        .filter((f) => {
          const cat = (f.properties as { category?: string })?.category ?? '';
          return cat.includes('수산시장') || cat.includes('어시장');
        })
        .map((f) => {
          const p = f.properties as Record<string, unknown>;
          return {
            name: String(p['name'] ?? p['market_nm'] ?? p['nm'] ?? ''),
            distance: calcDist(f.geometry as { type: string; coordinates: unknown }),
          };
        });

      // esi (해안선) — 기존 10개 행의 length만 갱신
      const esiFeatures = geojson.features.filter((f) => {
        const cat = (f.properties as { category?: string })?.category ?? '';
        return cat.includes('해안선') || cat.includes('ESI');
      });
      const esiLengthMap: Record<string, string> = {};
      esiFeatures.forEach((f) => {
        const p = f.properties as Record<string, unknown>;
        const code = String(p['esi_cd'] ?? '');
        const len = p['length_km'] ?? p['len_km'];
        if (code && len != null) esiLengthMap[code] = `${Number(len).toFixed(2)} km`;
      });
      const esiRows =
        esiFeatures.length > 0
          ? data.esi.map((row) => ({
              ...row,
              length:
                esiLengthMap[row.code.replace('ESI ', '')] ?? esiLengthMap[row.code] ?? row.length,
            }))
          : data.esi;

      // species (보호종·생물종) — 3개 고정 행 유지, species 컬럼만 갱신
      const SPECIES_MAP: Record<string, string[]> = {
        양서파충류: ['파충', '양서'],
        조류: ['조류'],
        포유류: ['포유'],
      };
      const speciesCollected: Record<string, string[]> = { 양서파충류: [], 조류: [], 포유류: [] };
      geojson.features.forEach((f) => {
        const cat = (f.properties as { category?: string })?.category ?? '';
        const p = f.properties as Record<string, unknown>;
        const nm = String(p['name'] ?? p['species_nm'] ?? '');
        if (!nm) return;
        for (const [row, kws] of Object.entries(SPECIES_MAP)) {
          if (kws.some((kw) => cat.includes(kw))) {
            speciesCollected[row].push(nm);
            break;
          }
        }
      });
      const hasSpecies = Object.values(speciesCollected).some((arr) => arr.length > 0);
      const speciesRows = hasSpecies
        ? data.species.map((row) => ({
            ...row,
            species: speciesCollected[row.category]?.join(', ') ?? row.species,
          }))
        : data.species;

      // habitat (서식지) — 타입별 면적 합산
      const habitatFeatures = geojson.features.filter((f) =>
        HABITAT_TYPES.some((t) =>
          ((f.properties as { category?: string })?.category ?? '').includes(t),
        ),
      );
      const habitatMap: Record<string, number> = {};
      habitatFeatures.forEach((f) => {
        const cat = (f.properties as { category?: string })?.category ?? '';
        const p = f.properties as Record<string, unknown>;
        habitatMap[cat] = (habitatMap[cat] ?? 0) + (p['area'] != null ? Number(p['area']) : 0);
      });
      const habitatRows =
        habitatFeatures.length > 0
          ? Object.entries(habitatMap).map(([type, area]) => ({
              type,
              area: area > 0 ? area.toFixed(2) : '',
            }))
          : data.habitat;

      // 단일 onChange 일괄 업데이트
      const updates: Partial<OilSpillReportData> = {};
      if (aquacultureRows.length > 0) updates.aquaculture = aquacultureRows;
      if (beachRows.length > 0) updates.beaches = beachRows;
      if (marketRows.length > 0) updates.markets = marketRows;
      if (esiFeatures.length > 0) updates.esi = esiRows;
      if (hasSpecies) updates.species = speciesRows;
      if (habitatFeatures.length > 0) updates.habitat = habitatRows;
      if (Object.keys(updates).length > 0) onChange({ ...data, ...updates });

      setMapVisible(true);
      // 다음 렌더 사이클 후 지도 초기화
      setTimeout(() => {
        if (!mapContainerRef.current) return;
        const map = new maplibregl.Map({
          container: mapContainerRef.current,
          style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
          center: [127.5, 35.5],
          zoom: 8,
          preserveDrawingBuffer: true,
        } as maplibregl.MapOptions);
        mapRef.current = map;
        map.on('load', () => {
          // 확산 파티클 — sensitive 레이어 아래 (예측 탭과 동일한 색상 로직)
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          map.addSource('particles', { type: 'geojson', data: particlesGeojson as any });
          // 과거 스텝: 회색 반투명
          map.addLayer({
            id: 'particles-past',
            type: 'circle',
            source: 'particles',
            filter: ['==', ['get', 'isLastStep'], false],
            paint: { 'circle-radius': 2.5, 'circle-color': '#828282', 'circle-opacity': 0.4 },
          });
          // 최신 스텝: 모델별 색상 (OpenDrift=파랑, POSEIDON=빨강)
          map.addLayer({
            id: 'particles-current',
            type: 'circle',
            source: 'particles',
            filter: ['==', ['get', 'isLastStep'], true],
            paint: {
              'circle-radius': 3,
              'circle-color': [
                'case',
                ['==', ['get', 'model'], 'OpenDrift'],
                '#3b82f6',
                ['==', ['get', 'model'], 'POSEIDON'],
                '#ef4444',
                '#06b6d4',
              ],
              'circle-opacity': 0.85,
            },
          });
          // 민감자원 레이어
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          map.addSource('sensitive', { type: 'geojson', data: filteredGeojson as any });
          map.addLayer({
            id: 'sensitive-fill',
            type: 'fill',
            source: 'sensitive',
            filter: ['==', '$type', 'Polygon'],
            paint: { 'fill-color': ['get', '_color'], 'fill-opacity': 0.4 },
          });
          map.addLayer({
            id: 'sensitive-line',
            type: 'line',
            source: 'sensitive',
            filter: ['==', '$type', 'Polygon'],
            paint: { 'line-color': ['get', '_color'], 'line-width': 1.5 },
          });
          map.addLayer({
            id: 'sensitive-circle',
            type: 'circle',
            source: 'sensitive',
            filter: ['==', '$type', 'Point'],
            paint: {
              'circle-radius': 6,
              'circle-color': ['get', '_color'],
              'circle-stroke-width': 1.5,
              'circle-stroke-color': '#fff',
            },
          });
          // fit bounds — spread + sensitive 합산
          const coords: [number, number][] = [];
          const collectCoords = (geom: { type: string; coordinates: unknown }) => {
            if (geom.type === 'Point') {
              coords.push(geom.coordinates as [number, number]);
            } else if (geom.type === 'Polygon') {
              const rings = geom.coordinates as [number, number][][];
              rings[0]?.forEach((c) => coords.push(c));
            } else if (geom.type === 'MultiPolygon') {
              const polys = geom.coordinates as [number, number][][][];
              polys.forEach((rings) => rings[0]?.forEach((c) => coords.push(c)));
            }
          };
          filteredGeojson.features.forEach((f) =>
            collectCoords(f.geometry as { type: string; coordinates: unknown }),
          );
          particlesGeojson.features.forEach((f) => {
            coords.push(f.geometry.coordinates as [number, number]);
          });
          if (coords.length > 0) {
            const lngs = coords.map((c) => c[0]);
            const lats = coords.map((c) => c[1]);
            map.fitBounds(
              [
                [Math.min(...lngs), Math.min(...lats)],
                [Math.max(...lngs), Math.max(...lats)],
              ],
              { padding: 60, maxZoom: 13 },
            );
          }
          // 사고 위치 마커 (캔버스 레이어 — 캡처에 포함)
          if (incLat != null && incLon != null) {
            map.addSource('incident-point', {
              type: 'geojson',
              data: {
                type: 'Feature',
                geometry: { type: 'Point', coordinates: [incLon, incLat] },
                properties: {},
              },
            });
            map.addLayer({
              id: 'incident-circle',
              type: 'circle',
              source: 'incident-point',
              paint: {
                'circle-radius': 7,
                'circle-color': '#ef4444',
                'circle-stroke-width': 2,
                'circle-stroke-color': '#ffffff',
              },
            });
            map.addLayer({
              id: 'incident-label',
              type: 'symbol',
              source: 'incident-point',
              layout: {
                'text-field': '사고위치',
                'text-size': 11,
                'text-offset': [0, 1.6],
                'text-anchor': 'top',
                'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
              },
              paint: {
                'text-color': '#ffffff',
                'text-halo-color': '#ef4444',
                'text-halo-width': 3,
              },
            });
          }
        });
      }, 100);
    } catch {
      alert('민감자원 지도 데이터를 불러오지 못했습니다.');
    } finally {
      setLoading(false);
    }
  };

  const handleCapture = () => {
    const map = mapRef.current;
    if (!map) return;
    setCapturing(true);
    map.once('idle', () => {
      const mapCanvas = map.getCanvas();
      const dpr = window.devicePixelRatio || 1;
      const W = mapCanvas.width;
      const H = mapCanvas.height;

      const composite = document.createElement('canvas');
      composite.width = W;
      composite.height = H;
      const ctx = composite.getContext('2d')!;

      // 지도 그리기
      ctx.drawImage(mapCanvas, 0, 0);

      // 범례 그리기
      const items = CATEGORY_COLORS.filter((c) => legendLabels.includes(c.label));
      if (items.length > 0) {
        const pad = 8 * dpr;
        const swSize = 12 * dpr;
        const lineH = 18 * dpr;
        const fontSize = 11 * dpr;
        const boxW = 130 * dpr;
        const boxH = pad * 2 + items.length * lineH;
        const lx = pad,
          ly = pad;

        ctx.fillStyle = 'rgba(255,255,255,0.88)';
        ctx.fillRect(lx, ly, boxW, boxH);
        ctx.strokeStyle = 'rgba(0,0,0,0.15)';
        ctx.lineWidth = dpr;
        ctx.strokeRect(lx, ly, boxW, boxH);

        items.forEach(({ color, label }, i) => {
          const iy = ly + pad + i * lineH;
          ctx.fillStyle = color;
          ctx.fillRect(lx + pad, iy + (lineH - swSize) / 2, swSize, swSize);
          ctx.fillStyle = '#1f2937';
          ctx.font = `${fontSize}px sans-serif`;
          ctx.fillText(label, lx + pad + swSize + 4 * dpr, iy + lineH / 2 + fontSize * 0.35);
        });
      }

      onChange({ ...data, sensitiveMapImage: composite.toDataURL('image/png') });
      setCapturing(false);
    });
    map.triggerRepaint();
  };

  const handleReset = () => {
    if (mapRef.current) {
      mapRef.current.remove();
      mapRef.current = null;
    }
    setMapVisible(false);
    setLegendLabels([]);
    onChange({ ...data, sensitiveMapImage: undefined });
  };

  useEffect(() => {
    return () => {
      mapRef.current?.remove();
    };
  }, []);

  // 뷰 모드: 이미지 있으면 표시, 없으면 플레이스홀더
  if (!editing) {
    if (data.sensitiveMapImage) {
      return (
        <img
          src={data.sensitiveMapImage}
          alt="민감자원 분포 지도"
          style={{
            width: '100%',
            height: 'auto',
            display: 'block',
            border: '1px solid #ddd',
            borderRadius: 4,
          }}
        />
      );
    }
    return <div style={S.mapPlaceholder}>민감자원 분포(10km 내) 지도</div>;
  }

  // 편집 모드: acdntSn 없음
  if (!acdntSn) {
    return <div style={S.mapPlaceholder}>민감자원 분포(10km 내) 지도</div>;
  }

  // 편집 모드: 캡처 이미지 있음
  if (data.sensitiveMapImage) {
    return (
      <div style={{ position: 'relative' }}>
        <img
          src={data.sensitiveMapImage}
          alt="민감자원 분포 지도"
          style={{
            width: '100%',
            height: 'auto',
            display: 'block',
            border: '1px solid #ddd',
            borderRadius: 4,
          }}
        />
        <button
          onClick={handleReset}
          style={{
            position: 'absolute',
            top: 8,
            right: 8,
            background: 'rgba(0,0,0,0.6)',
            color: '#fff',
            border: 'none',
            borderRadius: 4,
            padding: '3px 8px',
            fontSize: 11,
            cursor: 'pointer',
          }}
        >
          재캡처
        </button>
      </div>
    );
  }

  // 편집 모드: 지도 로드/캡처
  return (
    <div>
      {!mapVisible ? (
        <div style={{ ...S.mapPlaceholder, flexDirection: 'column', gap: 8 }}>
          <span>민감자원 분포(10km 내) 지도</span>
          <button
            onClick={handleLoad}
            disabled={loading}
            style={{
              background: '#0891b2',
              color: '#fff',
              border: 'none',
              borderRadius: 4,
              padding: '5px 14px',
              fontSize: 12,
              cursor: loading ? 'not-allowed' : 'pointer',
              opacity: loading ? 0.7 : 1,
            }}
          >
            {loading ? '불러오는 중...' : '지도 불러오기'}
          </button>
        </div>
      ) : (
        <div style={{ position: 'relative' }}>
          <div
            ref={mapContainerRef}
            style={{ width: '100%', height: 440, borderRadius: 4, overflow: 'hidden' }}
          />
          {legendLabels.length > 0 && (
            <div
              style={{
                position: 'absolute',
                top: 8,
                left: 8,
                background: 'rgba(255,255,255,0.88)',
                border: '1px solid rgba(0,0,0,0.15)',
                borderRadius: 4,
                padding: '6px 10px',
                pointerEvents: 'none',
              }}
            >
              {CATEGORY_COLORS.filter((c) => legendLabels.includes(c.label)).map(
                ({ color, label }) => (
                  <div
                    key={label}
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      gap: 6,
                      marginBottom: 3,
                      fontSize: 11,
                      color: '#1f2937',
                      whiteSpace: 'nowrap',
                    }}
                  >
                    <div style={{ width: 12, height: 12, background: color, flexShrink: 0 }} />
                    {label}
                  </div>
                ),
              )}
            </div>
          )}
          <div style={{ display: 'flex', gap: 8, marginTop: 6, justifyContent: 'flex-end' }}>
            <button
              onClick={handleReset}
              style={{
                background: 'transparent',
                color: '#6b7280',
                border: '1px solid #374151',
                borderRadius: 4,
                padding: '3px 10px',
                fontSize: 11,
                cursor: 'pointer',
              }}
            >
              취소
            </button>
            <button
              onClick={handleCapture}
              disabled={capturing}
              style={{
                background: '#0891b2',
                color: '#fff',
                border: 'none',
                borderRadius: 4,
                padding: '3px 12px',
                fontSize: 11,
                cursor: capturing ? 'not-allowed' : 'pointer',
                opacity: capturing ? 0.7 : 1,
              }}
            >
              {capturing ? '캡처 중...' : '이 화면으로 캡처'}
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
