import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
import { Map, useControl } from '@vis.gl/react-maplibre';
import { MapboxOverlay } from '@deck.gl/mapbox';
import { PolygonLayer, ScatterplotLayer } from '@deck.gl/layers';
import type { MapMouseEvent } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { useBaseMapStyle } from '@common/hooks/useBaseMapStyle';
import { S57EncOverlay } from '@common/components/map/S57EncOverlay';
import { useMapStore } from '@common/store/mapStore';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function DeckGLOverlay({ layers }: { layers: any[] }) {
  const overlay = useControl<MapboxOverlay>(() => new MapboxOverlay({ interleaved: true }));
  overlay.setProps({ layers });
  return null;
}

type WingAITab = 'detect' | 'change' | 'aoi';

const tabItems: { id: WingAITab; label: string; icon: string; desc: string }[] = [
  {
    id: 'detect',
    label: '객체 탐지',
    icon: '🎯',
    desc: '위성/드론 영상에서 선박·차량·시설물 자동 탐지 및 분류',
  },
  {
    id: 'change',
    label: '변화 감지',
    icon: '🔄',
    desc: '동일 지역 다시점 영상 비교 분석 (Before/After)',
  },
  {
    id: 'aoi',
    label: '연안자동감지',
    icon: '📍',
    desc: '연안 관심지역 등록 → 변화 자동 감지 및 알림',
  },
];

export function WingAI() {
  const [activeTab, setActiveTab] = useState<WingAITab>('detect');

  return (
    <div className="overflow-y-auto px-6 pt-1 pb-2">
      {/* 헤더 */}
      <div className="flex items-center gap-3 mb-4 h-9">
        <div className="flex items-center gap-2 shrink-0">
          <div
            className="w-7 h-7 rounded-md flex items-center justify-center text-body-2"
            style={{
              background: 'rgba(6,182,212,0.15)',
              border: '1px solid rgba(6,182,212,0.3)',
            }}
          >
            🤖
          </div>
          <div className="text-label-1 font-bold font-korean text-fg">AI 탐지/분석</div>
          {/* <span
            className="text-caption px-1.5 py-0.5 rounded font-bold"
            style={{
              background: 'color-mix(in srgb, var(--color-tertiary) 12%, transparent)',
              color: 'var(--color-tertiary)',
              border: '1px solid rgba(168,85,247,.25)',
            }}
          >
            WingAI
          </span> */}
        </div>
        <div className="flex gap-1 h-7">
          {tabItems.map((t) => (
            <button
              key={t.id}
              onClick={() => setActiveTab(t.id)}
              className="px-2.5 h-full rounded text-caption font-bold font-korean cursor-pointer border transition-colors"
              style={
                activeTab === t.id
                  ? {
                      background: 'rgba(6,182,212,.08)',
                      borderColor: 'rgba(6,182,212,.3)',
                      color: 'var(--color-accent)',
                    }
                  : {
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--fg-disabled)',
                    }
              }
            >
              {/* {t.icon} */}
              {t.label}
            </button>
          ))}
        </div>
      </div>

      {/* 탭 콘텐츠 */}
      {activeTab === 'detect' && <DetectPanel />}
      {activeTab === 'change' && <ChangeDetectPanel />}
      {activeTab === 'aoi' && <AoiPanel />}
    </div>
  );
}

/* ─── 객체 탐지 패널 (MMSI 선종 불일치 탐지) ─────────── */
type MismatchStatus = '불일치' | '의심' | '정상' | '확인중';

interface VesselDetection {
  id: string;
  mmsi: string;
  vesselName: string;
  /** AIS 등록 선종 */
  aisType: string;
  /** AI 영상 분석 선종 */
  detectedType: string;
  /** 불일치 여부 */
  mismatch: boolean;
  status: MismatchStatus;
  confidence: string;
  coord: string;
  lon: number;
  lat: number;
  time: string;
  detail: string;
}

function DetectPanel() {
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [filterStatus, setFilterStatus] = useState<MismatchStatus | '전체'>('전체');
  const currentMapStyle = useBaseMapStyle();
  const mapToggles = useMapStore((s) => s.mapToggles);

  const detections: VesselDetection[] = [
    {
      id: 'VD-001',
      mmsi: '440123456',
      vesselName: 'OCEAN GLORY',
      aisType: '화물선',
      detectedType: '유조선',
      mismatch: true,
      status: '불일치',
      confidence: '94.2%',
      coord: '33.24°N 126.50°E',
      lon: 126.5,
      lat: 33.24,
      time: '14:23',
      detail: 'AIS 화물선 등록 → 영상 분석 결과 유조선 선형 + 탱크 구조 탐지',
    },
    {
      id: 'VD-002',
      mmsi: '441987654',
      vesselName: 'SEA PHOENIX',
      aisType: '유조선',
      detectedType: '화물선',
      mismatch: true,
      status: '불일치',
      confidence: '91.7%',
      coord: '34.73°N 127.68°E',
      lon: 127.68,
      lat: 34.73,
      time: '14:18',
      detail: 'AIS 유조선 등록 → 영상 분석 결과 컨테이너 적재 확인, 화물선 판정',
    },
    {
      id: 'VD-003',
      mmsi: '440555123',
      vesselName: 'DONGBANG 7',
      aisType: '어선',
      detectedType: '화물선',
      mismatch: true,
      status: '의심',
      confidence: '78.3%',
      coord: '35.15°N 129.13°E',
      lon: 129.13,
      lat: 35.15,
      time: '14:10',
      detail: 'AIS 어선 등록 → 선체 규모 및 구조가 어선 대비 과대, 화물선 의심',
    },
    {
      id: 'VD-004',
      mmsi: '440678901',
      vesselName: 'KOREA STAR',
      aisType: '화물선',
      detectedType: '화물선',
      mismatch: false,
      status: '정상',
      confidence: '97.8%',
      coord: '34.80°N 126.37°E',
      lon: 126.37,
      lat: 34.8,
      time: '14:05',
      detail: 'AIS 등록 선종과 영상 분석 결과 일치',
    },
    {
      id: 'VD-005',
      mmsi: 'N/A',
      vesselName: '미식별',
      aisType: 'AIS 미수신',
      detectedType: '유조선',
      mismatch: true,
      status: '확인중',
      confidence: '85.6%',
      coord: '33.11°N 126.27°E',
      lon: 126.27,
      lat: 33.11,
      time: '14:01',
      detail: 'AIS 신호 없음 → 위성 SAR로 유조선급 선형 탐지, 불법 운항 의심',
    },
    {
      id: 'VD-006',
      mmsi: '440234567',
      vesselName: 'BUSAN EXPRESS',
      aisType: '컨테이너선',
      detectedType: '유조선',
      mismatch: true,
      status: '불일치',
      confidence: '89.1%',
      coord: '35.05°N 129.10°E',
      lon: 129.1,
      lat: 35.05,
      time: '13:55',
      detail: 'AIS 컨테이너선 → 갑판 컨테이너 미확인, 탱크 구조 감지',
    },
    {
      id: 'VD-007',
      mmsi: '440345678',
      vesselName: 'JEJU BREEZE',
      aisType: '여객선',
      detectedType: '여객선',
      mismatch: false,
      status: '정상',
      confidence: '98.1%',
      coord: '33.49°N 126.52°E',
      lon: 126.52,
      lat: 33.49,
      time: '13:50',
      detail: 'AIS 등록 선종과 영상 분석 결과 일치',
    },
  ];

  const mismatchCount = detections.filter((d) => d.mismatch).length;
  const confirmingCount = detections.filter((d) => d.status === '확인중').length;

  const stats = [
    { value: String(detections.length), label: '분석 선박', color: 'var(--fg-default)' },
    { value: String(mismatchCount), label: '선종 불일치', color: 'var(--fg-default)' },
    { value: String(confirmingCount), label: '확인 중', color: 'var(--fg-default)' },
    {
      value: String(detections.filter((d) => !d.mismatch).length),
      label: '정상',
      color: 'var(--fg-default)',
    },
  ];

  const filtered =
    filterStatus === '전체' ? detections : detections.filter((d) => d.status === filterStatus);

  const statusStyle = (s: MismatchStatus) => {
    if (s === '불일치')
      return {
        background: 'color-mix(in srgb, var(--color-danger) 12%, transparent)',
        color: 'var(--color-danger)',
        border: '1px solid color-mix(in srgb, var(--color-danger) 25%, transparent)',
      };
    if (s === '의심')
      return {
        background: 'color-mix(in srgb, var(--color-caution) 12%, transparent)',
        color: 'var(--color-caution)',
        border: '1px solid color-mix(in srgb, var(--color-caution) 25%, transparent)',
      };
    if (s === '확인중')
      return {
        background: 'rgba(6,182,212,.08)',
        color: 'var(--color-accent)',
        border: '1px solid rgba(6,182,212,.25)',
      };
    return {
      background: 'color-mix(in srgb, var(--color-success) 12%, transparent)',
      color: 'var(--color-success)',
      border: '1px solid color-mix(in srgb, var(--color-success) 25%, transparent)',
    };
  };

  const filters: (MismatchStatus | '전체')[] = ['전체', '불일치', '의심', '확인중', '정상'];

  return (
    <div>
      {/* 통계 카드 */}
      <div className="grid grid-cols-4 gap-3 mb-5">
        {stats.map((s, i) => (
          <div key={i} className="bg-bg-elevated border border-stroke rounded-md p-3.5 text-center">
            <div className="text-[22px] font-bold font-mono" style={{ color: s.color }}>
              {s.value}
            </div>
            <div className="text-caption text-fg-disabled mt-1 font-korean">{s.label}</div>
          </div>
        ))}
      </div>

      <div className="grid grid-cols-[1fr_380px] gap-4">
        {/* 탐지 결과 지도 */}
        <div
          className="bg-bg-elevated border border-stroke rounded-md overflow-hidden"
          style={{ minHeight: 480 }}
        >
          <div className="flex items-center justify-between px-4 py-3 border-b border-stroke">
            <div className="text-label-2 font-bold font-korean text-fg">
              🎯 선종 불일치 탐지 지도
            </div>
            <div className="text-caption text-fg-disabled font-mono">{filtered.length}척 표시</div>
          </div>
          <div className="relative" style={{ height: 440 }}>
            <Map
              initialViewState={{ longitude: 127.5, latitude: 34.0, zoom: 6.5 }}
              style={{ width: '100%', height: '100%' }}
              mapStyle={currentMapStyle}
              attributionControl={false}
            >
              <S57EncOverlay visible={mapToggles['s57'] ?? false} />
              <DeckGLOverlay
                layers={[
                  new ScatterplotLayer({
                    id: 'vessel-detect-markers',
                    data: filtered,
                    getPosition: (d: VesselDetection) => [d.lon, d.lat],
                    getRadius: (d: VesselDetection) => (selectedId === d.id ? 10 : 7),
                    radiusUnits: 'pixels' as const,
                    getFillColor: (d: VesselDetection) => {
                      if (d.status === '불일치') return [239, 68, 68, 200];
                      if (d.status === '의심') return [234, 179, 8, 200];
                      if (d.status === '확인중') return [6, 182, 212, 200];
                      return [34, 197, 94, 160];
                    },
                    getLineColor: [255, 255, 255, 255],
                    lineWidthMinPixels: 2,
                    stroked: true,
                    pickable: true,
                    onClick: ({ object }: { object: VesselDetection }) => {
                      if (object) setSelectedId(object.id === selectedId ? null : object.id);
                    },
                    updateTriggers: { getRadius: [selectedId] },
                  }),
                ]}
              />
            </Map>
            {/* 범례 */}
            <div className="absolute bottom-3 left-3 bg-bg-elevated/90 border border-stroke rounded px-3 py-2 backdrop-blur-sm">
              <div className="flex items-center gap-3">
                {[
                  { color: 'var(--color-danger)', label: '불일치' },
                  { color: 'var(--color-caution)', label: '의심' },
                  { color: 'var(--color-accent)', label: '확인중' },
                  { color: 'var(--color-success)', label: '정상' },
                ].map((l) => (
                  <div key={l.label} className="flex items-center gap-1">
                    <div className="w-2.5 h-2.5 rounded-full" style={{ background: l.color }} />
                    <span className="text-caption font-korean text-fg-disabled">{l.label}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>

        {/* 탐지 목록 */}
        <div
          className="bg-bg-elevated border border-stroke rounded-md overflow-hidden flex flex-col"
          style={{ maxHeight: 520 }}
        >
          <div className="px-4 py-3 border-b border-stroke shrink-0">
            <div className="flex items-center justify-between mb-2">
              <div className="text-label-2 font-bold font-korean text-fg">
                📋 MMSI 선종 검증 목록
              </div>
              <div className="text-caption text-fg-disabled font-mono">{filtered.length}건</div>
            </div>
            <div className="flex gap-1">
              {filters.map((f) => (
                <button
                  key={f}
                  onClick={() => setFilterStatus(f)}
                  className="px-2 py-0.5 rounded text-caption font-bold font-korean cursor-pointer border transition-colors"
                  style={
                    filterStatus === f
                      ? {
                          background: 'rgba(6,182,212,.08)',
                          borderColor: 'rgba(6,182,212,.3)',
                          color: 'var(--color-accent)',
                        }
                      : {
                          background: 'var(--bg-card)',
                          borderColor: 'var(--stroke-default)',
                          color: 'var(--fg-disabled)',
                        }
                  }
                >
                  {f}
                </button>
              ))}
            </div>
          </div>
          <div className="divide-y divide-stroke overflow-y-auto flex-1">
            {filtered.map((d) => (
              <div
                key={d.id}
                onClick={() => setSelectedId(selectedId === d.id ? null : d.id)}
                className="px-4 py-3 hover:bg-bg-surface-hover/30 transition-colors cursor-pointer"
                style={{ background: selectedId === d.id ? 'rgba(6,182,212,.04)' : undefined }}
              >
                <div className="flex items-center justify-between mb-1">
                  <div className="flex items-center gap-2">
                    <span className="text-caption font-mono text-fg-disabled">{d.id}</span>
                    <span className="text-caption font-bold font-korean text-fg">
                      {d.vesselName}
                    </span>
                  </div>
                  <span
                    className="px-1.5 py-0.5 rounded text-caption font-bold font-korean"
                    style={statusStyle(d.status)}
                  >
                    {d.status}
                  </span>
                </div>
                {/* 선종 비교 */}
                <div className="flex items-center gap-1.5 mt-1.5">
                  <span className="text-caption font-korean text-fg">AIS: {d.aisType}</span>
                  {d.mismatch && <span className="text-caption text-fg-disabled">≠</span>}
                  {!d.mismatch && <span className="text-caption text-fg-disabled">=</span>}
                  <span className="text-caption font-korean text-fg">AI: {d.detectedType}</span>
                </div>
                <div className="flex items-center gap-3 mt-1.5 text-caption text-fg-disabled font-mono">
                  <span>MMSI {d.mmsi}</span>
                  <span>{d.coord}</span>
                  <span>{d.time}</span>
                  <span>신뢰도 {d.confidence}</span>
                </div>
                {/* 펼침: 상세 */}
                {selectedId === d.id && (
                  <div
                    className="mt-2 px-3 py-2 rounded text-caption font-korean"
                    style={{
                      background: 'rgba(6,182,212,.04)',
                      border: '1px solid rgba(6,182,212,.12)',
                      color: 'var(--fg-sub)',
                    }}
                  >
                    {d.detail}
                  </div>
                )}
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ─── 변화 감지 패널 (복합 정보원 시점 비교) ──────────── */
type SourceType = 'satellite' | 'cctv' | 'drone' | 'ais';

interface SourceConfig {
  id: SourceType;
  label: string;
  icon: string;
  color: string;
  desc: string;
}

const SOURCES: SourceConfig[] = [
  {
    id: 'satellite',
    label: '위성영상',
    icon: '🛰',
    color: 'var(--color-accent)',
    desc: 'KOMPSAT-3A / Sentinel SAR 수신 영상',
  },
  {
    id: 'cctv',
    label: 'CCTV',
    icon: '📹',
    color: 'var(--color-info)',
    desc: 'KHOA / KBS 해안 CCTV 스냅샷',
  },
  {
    id: 'drone',
    label: '드론',
    icon: '🛸',
    color: 'var(--color-success)',
    desc: '정밀 촬영 / 열화상 이미지',
  },
  {
    id: 'ais',
    label: 'AIS',
    icon: '🚢',
    color: 'var(--color-warning)',
    desc: '선박 위치·항적·MMSI 궤적',
  },
];

interface ChangeRecord {
  id: string;
  area: string;
  type: string;
  date1: string;
  time1: string;
  date2: string;
  time2: string;
  severity: '심각' | '보통' | '낮음';
  detail: string;
  sources: SourceType[];
  crossRef?: string;
  /** 각 정보원별 AS-IS 시점 요약 */
  asIsDetail: Partial<Record<SourceType, string>>;
  /** 각 정보원별 현재 시점 요약 */
  nowDetail: Partial<Record<SourceType, string>>;
}

function ChangeDetectPanel() {
  const [layers, setLayers] = useState<Record<SourceType, boolean>>({
    satellite: true,
    cctv: true,
    drone: true,
    ais: true,
  });
  const [sourceFilter, setSourceFilter] = useState<SourceType | 'all'>('all');
  const [selectedChange, setSelectedChange] = useState<string | null>(null);

  const toggleLayer = (id: SourceType) => setLayers((prev) => ({ ...prev, [id]: !prev[id] }));
  const activeCount = Object.values(layers).filter(Boolean).length;

  const changes: ChangeRecord[] = [
    {
      id: 'CHG-001',
      area: '여수항 북측 해안',
      type: '선박 이동',
      date1: '03-14',
      time1: '14:00',
      date2: '03-16',
      time2: '14:23',
      severity: '보통',
      detail: '정박 선박 3척 → 7척 (증가)',
      sources: ['satellite', 'ais', 'cctv'],
      crossRef: 'AIS MMSI 440123456 외 3척 신규 입항 — 위성+CCTV 동시 확인',
      asIsDetail: {
        satellite: '정박 선박 3척 식별',
        ais: 'MMSI 3건 정박 상태',
        cctv: '여수 오동도 CCTV 정상',
      },
      nowDetail: {
        satellite: '선박 7척 식별 (4척 증가)',
        ais: 'MMSI 7건 (신규 4건 입항)',
        cctv: '여수 오동도 CCTV 선박 증가 확인',
      },
    },
    {
      id: 'CHG-002',
      area: '제주 서귀포 해상',
      type: '유막 확산',
      date1: '03-15',
      time1: '10:30',
      date2: '03-16',
      time2: '14:23',
      severity: '심각',
      detail: '유막 면적 2.1km² → 4.8km² (확산)',
      sources: ['satellite', 'drone', 'cctv', 'ais'],
      crossRef: '4개 정보원 교차확인 — 유막 남동 방향 확산 일치',
      asIsDetail: {
        satellite: 'SAR 유막 2.1km² 탐지',
        drone: '열화상 유막 경계 포착',
        cctv: '서귀포 카메라 해면 이상 없음',
        ais: '인근 유조선 1척 정박',
      },
      nowDetail: {
        satellite: 'SAR 유막 4.8km² 확산',
        drone: '열화상 유막 남동 2.7km 확대',
        cctv: '서귀포 카메라 해면 변색 감지',
        ais: '유조선 이탈, 방제선 2척 진입',
      },
    },
    {
      id: 'CHG-003',
      area: '부산항 외항',
      type: '방제장비 배치',
      date1: '03-10',
      time1: '09:00',
      date2: '03-16',
      time2: '14:23',
      severity: '낮음',
      detail: '부유식 오일펜스 신규 배치 확인',
      sources: ['drone', 'cctv'],
      crossRef: 'CCTV 부산항 #204 + 드론 정밀 촬영 일치',
      asIsDetail: { drone: '오일펜스 미배치', cctv: '부산 민락항 CCTV 해상 장비 없음' },
      nowDetail: { drone: '오일펜스 300m 배치 확인', cctv: '부산 민락항 CCTV 오일펜스 포착' },
    },
    {
      id: 'CHG-004',
      area: '통영 해역 남측',
      type: '미식별 선박',
      date1: '03-13',
      time1: '22:00',
      date2: '03-16',
      time2: '14:23',
      severity: '보통',
      detail: 'AIS 미송출 선박 2척 위성 포착',
      sources: ['satellite', 'ais'],
      crossRef: 'AIS 미등록 — 위성 SAR 반사 신호로 탐지, 불법 조업 의심',
      asIsDetail: { satellite: '해역 내 선박 신호 없음', ais: '등록 선박 0척' },
      nowDetail: { satellite: 'SAR 반사 2건 포착 (선박 추정)', ais: 'MMSI 미수신 — 미식별 선박' },
    },
    {
      id: 'CHG-005',
      area: '인천 연안부두',
      type: '야간 이상징후',
      date1: '03-15',
      time1: '03:42',
      date2: '03-16',
      time2: '03:45',
      severity: '심각',
      detail: 'CCTV 야간 유출 의심 + AIS 정박선 이탈',
      sources: ['cctv', 'ais'],
      crossRef: 'KBS CCTV #9981 03:42 해면 반사 이상 → AIS 03:45 정박선 이탈 연계',
      asIsDetail: { cctv: '인천 연안부두 CCTV 야간 정상', ais: '정박선 5척 정상 정박' },
      nowDetail: {
        cctv: '03:42 해면 반사광 이상 감지',
        ais: '03:45 정박선 1척 이탈 (MMSI 441987654)',
      },
    },
    {
      id: 'CHG-006',
      area: '마라도 주변 해역',
      type: '해안선 변화',
      date1: '03-12',
      time1: '11:00',
      date2: '03-16',
      time2: '11:15',
      severity: '낮음',
      detail: '해안 퇴적물 분포 변경 감지',
      sources: ['satellite', 'drone'],
      crossRef: '위성 다분광 + 드론 정밀 촬영 퇴적 방향 확인',
      asIsDetail: { satellite: '해안선 퇴적 분포 기준점', drone: '미촬영' },
      nowDetail: { satellite: '퇴적 남서 방향 이동 감지', drone: '정밀 촬영으로 퇴적 경계 확인' },
    },
  ];

  const severityStyle = (s: '심각' | '보통' | '낮음') => {
    if (s === '심각')
      return {
        background: 'color-mix(in srgb, var(--color-danger) 12%, transparent)',
        color: 'var(--color-danger)',
        border: '1px solid color-mix(in srgb, var(--color-danger) 25%, transparent)',
      };
    if (s === '보통')
      return {
        background: 'color-mix(in srgb, var(--color-caution) 12%, transparent)',
        color: 'var(--color-caution)',
        border: '1px solid color-mix(in srgb, var(--color-caution) 25%, transparent)',
      };
    return {
      background: 'color-mix(in srgb, var(--color-success) 12%, transparent)',
      color: 'var(--color-success)',
      border: '1px solid color-mix(in srgb, var(--color-success) 25%, transparent)',
    };
  };

  const sourceStyle = (src: SourceConfig, active = true) =>
    active
      ? { background: `${src.color}18`, color: src.color, border: `1px solid ${src.color}40` }
      : {
          background: 'var(--bg-card)',
          color: 'var(--fg-disabled)',
          border: '1px solid var(--stroke-default)',
          opacity: 0.5,
        };

  const filteredChanges =
    sourceFilter === 'all' ? changes : changes.filter((c) => c.sources.includes(sourceFilter));

  return (
    <div>
      {/* 레이어 토글 바 */}
      <div className="flex items-center gap-3 mb-4">
        <div className="text-caption font-bold font-korean text-fg-disabled shrink-0">
          오버레이 레이어
        </div>
        <div className="flex gap-1.5">
          {SOURCES.map((s) => (
            <button
              key={s.id}
              onClick={() => toggleLayer(s.id)}
              className="px-2.5 py-1.5 rounded text-caption font-bold font-korean cursor-pointer border transition-all"
              style={sourceStyle(s, layers[s.id])}
            >
              <span className="mr-1">{layers[s.id] ? '◉' : '○'}</span>
              {/* {s.icon}  */}
              {s.label}
            </button>
          ))}
        </div>
        <div className="text-caption text-fg-disabled font-mono ml-auto">
          {activeCount}/4 레이어 활성
        </div>
      </div>

      {/* AS-IS / 현재 시점 비교 뷰 */}
      <div className="grid grid-cols-2 gap-4 mb-4" style={{ minHeight: 400 }}>
        {/* AS-IS 시점 */}
        <div className="bg-bg-elevated border border-stroke rounded-md overflow-hidden">
          <div
            className="flex items-center justify-between px-4 py-2.5 border-b border-stroke"
            style={{ background: 'rgba(6,182,212,.05)' }}
          >
            <div className="flex items-center gap-2">
              <span
                className="text-label-2 font-bold font-korean"
                style={{ color: 'var(--color-accent)' }}
              >
                AS-IS
              </span>
              <span
                className="text-caption px-1.5 py-0.5 rounded font-bold"
                style={{
                  background: 'rgba(6,182,212,.12)',
                  color: 'var(--color-accent)',
                  border: '1px solid rgba(6,182,212,.25)',
                }}
              >
                과거 시점
              </span>
            </div>
            <div className="flex items-center gap-2">
              <input
                type="date"
                defaultValue="2026-03-14"
                className="text-caption font-mono px-2 py-1 rounded border outline-none"
                style={{
                  background: 'var(--bg-card)',
                  borderColor: 'var(--stroke-default)',
                  color: 'var(--fg-sub)',
                }}
              />
              <input
                type="time"
                defaultValue="14:00"
                className="text-caption font-mono px-2 py-1 rounded border outline-none"
                style={{
                  background: 'var(--bg-card)',
                  borderColor: 'var(--stroke-default)',
                  color: 'var(--fg-sub)',
                }}
              />
            </div>
          </div>
          {/* 활성 레이어 표시 */}
          {/* <div
            className="flex gap-1 px-3 py-2 border-b"
            style={{ borderColor: 'rgba(255,255,255,.04)' }}
          >
            {SOURCES.filter((s) => layers[s.id]).map((s) => (
              <span
                key={s.id}
                className="px-1.5 py-0.5 rounded text-caption font-bold"
                style={sourceStyle(s)}
              >
                {s.icon} {s.label}
              </span>
            ))}
            {activeCount === 0 && (
              <span className="text-caption text-fg-disabled font-korean">레이어를 선택하세요</span>
            )}
          </div> */}
          {/* 지도 플레이스홀더 */}
          <div
            className="flex items-center justify-center text-fg-disabled"
            style={{ height: 320 }}
          >
            <div className="text-center">
              <div className="flex justify-center gap-2 text-2xl mb-3 opacity-30">
                {SOURCES.filter((s) => layers[s.id]).map((s) => (
                  <span key={s.id}>{s.icon}</span>
                ))}
              </div>
              <div className="text-label-2 font-korean text-fg-disabled">
                과거 시점 복합 오버레이
              </div>
              <div className="text-caption text-fg-disabled mt-1">
                {SOURCES.filter((s) => layers[s.id])
                  .map((s) => s.label)
                  .join(' + ')}{' '}
                통합 표시
              </div>
            </div>
          </div>
        </div>

        {/* 현재 시점 */}
        <div className="bg-bg-elevated border border-stroke rounded-md overflow-hidden">
          <div
            className="flex items-center justify-between px-4 py-2.5 border-b border-stroke"
            style={{ background: 'rgba(6,182,212,.05)' }}
          >
            <div className="flex items-center gap-2">
              <span
                className="text-label-2 font-bold font-korean"
                style={{ color: 'var(--color-accent)' }}
              >
                현재
              </span>
              <span
                className="text-caption px-1.5 py-0.5 rounded font-bold"
                style={{
                  background: 'rgba(6,182,212,.12)',
                  color: 'var(--color-accent)',
                  border: '1px solid rgba(6,182,212,.25)',
                }}
              >
                NOW
              </span>
            </div>
            <span className="text-caption text-fg-disabled font-mono">2026-03-16 14:23</span>
          </div>
          {/* 활성 레이어 표시 */}
          {/* <div
            className="flex gap-1 px-3 py-2 border-b"
            style={{ borderColor: 'rgba(255,255,255,.04)' }}
          >
            {SOURCES.filter((s) => layers[s.id]).map((s) => (
              <span
                key={s.id}
                className="px-1.5 py-0.5 rounded text-caption font-bold"
                style={sourceStyle(s)}
              >
                {s.icon} {s.label}
              </span>
            ))}
            {activeCount === 0 && (
              <span className="text-caption text-fg-disabled font-korean">레이어를 선택하세요</span>
            )}
          </div> */}
          {/* 지도 플레이스홀더 */}
          <div
            className="flex items-center justify-center text-fg-disabled"
            style={{ height: 320 }}
          >
            <div className="text-center">
              <div className="flex justify-center gap-2 text-2xl mb-3 opacity-30">
                {SOURCES.filter((s) => layers[s.id]).map((s) => (
                  <span key={s.id}>{s.icon}</span>
                ))}
              </div>
              <div className="text-label-2 font-korean text-fg-disabled">
                현재 시점 복합 오버레이
              </div>
              <div className="text-caption text-fg-disabled mt-1">
                {SOURCES.filter((s) => layers[s.id])
                  .map((s) => s.label)
                  .join(' + ')}{' '}
                실시간 통합
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* 복합 변화 감지 목록 */}
      <div className="bg-bg-elevated border border-stroke rounded-md overflow-hidden">
        <div className="flex items-center justify-between px-4 py-3 border-b border-stroke">
          <div className="text-label-2 font-bold font-korean text-fg">
            🔄 복합 변화 감지 타임라인
          </div>
          <div className="flex items-center gap-2">
            <div className="flex gap-1">
              <button
                onClick={() => setSourceFilter('all')}
                className="px-2 py-0.5 rounded text-caption font-bold font-korean cursor-pointer border transition-colors"
                style={
                  sourceFilter === 'all'
                    ? {
                        background: 'rgba(6,182,212,.08)',
                        borderColor: 'rgba(6,182,212,.3)',
                        color: 'var(--color-accent)',
                      }
                    : {
                        background: 'var(--bg-card)',
                        borderColor: 'var(--stroke-default)',
                        color: 'var(--fg-disabled)',
                      }
                }
              >
                전체
              </button>
              {SOURCES.map((s) => (
                <button
                  key={s.id}
                  onClick={() => setSourceFilter(s.id)}
                  className="px-2 py-0.5 rounded text-caption font-bold font-korean cursor-pointer border transition-colors"
                  style={
                    sourceFilter === s.id
                      ? {
                          background: 'rgba(6,182,212,.08)',
                          borderColor: 'rgba(6,182,212,.3)',
                          color: 'var(--color-accent)',
                        }
                      : {
                          background: 'var(--bg-card)',
                          borderColor: 'var(--stroke-default)',
                          color: 'var(--fg-disabled)',
                        }
                  }
                >
                  {s.label}
                </button>
              ))}
            </div>
            <div className="text-caption text-fg-disabled font-mono">
              {filteredChanges.length}건
            </div>
          </div>
        </div>

        {/* 데이터 행 */}
        {filteredChanges.map((c) => {
          const isOpen = selectedChange === c.id;
          return (
            <div key={c.id} className="border-b" style={{ borderColor: 'rgba(255,255,255,.04)' }}>
              {/* 요약 행 */}
              <div
                onClick={() => setSelectedChange(isOpen ? null : c.id)}
                className="grid gap-0 px-4 py-3 items-center hover:bg-bg-surface-hover/30 transition-colors cursor-pointer"
                style={{
                  gridTemplateColumns: '52px 1fr 200px 150px 52px',
                  background: isOpen ? 'rgba(6,182,212,.04)' : undefined,
                }}
              >
                <div className="text-caption font-mono text-fg-disabled">{c.id}</div>
                <div>
                  <div className="flex items-center gap-2">
                    <span className="text-label-2 font-semibold text-fg font-korean">{c.area}</span>
                    <span
                      className="text-caption font-korean"
                      style={{ color: 'var(--fg-disabled)' }}
                    >
                      {c.type}
                    </span>
                  </div>
                  <div className="text-caption text-fg-disabled font-korean mt-0.5">{c.detail}</div>
                </div>
                <div className="flex flex-wrap gap-1">
                  {c.sources.map((sid) => {
                    const cfg = SOURCES.find((s) => s.id === sid)!;
                    return (
                      <span
                        key={sid}
                        className="px-1.5 py-0.5 rounded text-caption text-fg"
                        style={{
                          background: 'transparent',
                          border: `1px solid color-mix(in srgb, ${cfg.color} 40%, transparent)`,
                          color: `${cfg.color}`,
                        }}
                      >
                        {cfg.label}
                      </span>
                    );
                  })}
                </div>
                <div className="text-caption font-mono">
                  <span className="text-fg">
                    {c.date1} {c.time1}
                  </span>
                  <span className="text-fg-disabled mx-1">→</span>
                  <span className="text-fg">
                    {c.date2} {c.time2}
                  </span>
                </div>
                <div>
                  <span
                    className="px-1.5 py-0.5 rounded text-caption font-bold font-korean"
                    style={severityStyle(c.severity)}
                  >
                    {c.severity}
                  </span>
                </div>
              </div>

              {/* 펼침: 정보원별 AS-IS → 현재 상세 */}
              {isOpen && (
                <div className="px-4 pb-3 pt-1" style={{ background: 'rgba(6,182,212,.02)' }}>
                  {/* 교차검증 */}
                  {c.crossRef && (
                    <div
                      className="mb-3 px-3 py-2 rounded text-caption font-korean"
                      style={{
                        background: 'rgba(6,182,212,.06)',
                        border: '1px solid rgba(6,182,212,.15)',
                        color: 'var(--fg-sub)',
                      }}
                    >
                      <span className="font-bold" style={{ color: 'var(--color-accent)' }}>
                        교차검증
                      </span>{' '}
                      {c.crossRef}
                    </div>
                  )}
                  {/* 정보원별 비교 그리드 */}
                  <div className="grid gap-2">
                    <div
                      className="grid gap-0 px-3 py-1.5"
                      style={{ gridTemplateColumns: '90px 1fr 1fr' }}
                    >
                      <div className="text-caption font-bold text-fg-disabled font-korean">
                        정보원
                      </div>
                      <div className="text-caption font-bold font-korean text-fg">
                        AS-IS ({c.date1} {c.time1})
                      </div>
                      <div className="text-caption font-bold font-korean text-fg">
                        현재 ({c.date2} {c.time2})
                      </div>
                    </div>
                    {c.sources.map((sid) => {
                      const cfg = SOURCES.find((s) => s.id === sid)!;
                      return (
                        <div
                          key={sid}
                          className="grid gap-0 px-3 py-2 rounded"
                          style={{
                            gridTemplateColumns: '90px 1fr 1fr',
                            background: `${cfg.color}06`,
                            border: `1px solid ${cfg.color}15`,
                          }}
                        >
                          <div className="flex items-center gap-1.5">
                            <span
                              className="text-caption font-bold px-1.5 py-0.5 rounded"
                              style={sourceStyle(cfg)}
                            >
                              {cfg.icon} {cfg.label}
                            </span>
                          </div>
                          <div className="text-caption font-korean text-fg-disabled">
                            {c.asIsDetail[sid] || '-'}
                          </div>
                          <div className="text-caption font-korean text-fg">
                            {c.nowDetail[sid] || '-'}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ─── 연안자동감지 패널 ──────────────────────────────── */
type ZoneStatus = '정상' | '경보' | '주의';
type MonitorSource = 'satellite' | 'cctv' | 'drone' | 'ais';

interface MonitorSourceConfig {
  id: MonitorSource;
  label: string;
  icon: string;
  color: string;
  desc: string;
}

const MONITOR_SOURCES: MonitorSourceConfig[] = [
  {
    id: 'satellite',
    label: '위성영상',
    icon: '🛰',
    color: 'var(--color-accent)',
    desc: 'KOMPSAT/Sentinel 주기 촬영',
  },
  {
    id: 'cctv',
    label: 'CCTV',
    icon: '📹',
    color: 'var(--color-info)',
    desc: 'KHOA/KBS 해안 CCTV 실시간',
  },
  {
    id: 'drone',
    label: '드론',
    icon: '🛸',
    color: 'var(--color-success)',
    desc: '드론 정밀 촬영 / 열화상',
  },
  {
    id: 'ais',
    label: 'AIS',
    icon: '🚢',
    color: 'var(--color-warning)',
    desc: '선박 위치·항적 실시간 수신',
  },
];

interface MonitorZone {
  id: string;
  name: string;
  interval: string;
  lastCheck: string;
  status: ZoneStatus;
  alerts: number;
  polygon: [number, number][];
  color: string;
  monitoring: boolean;
  /** 활성 모니터링 소스 */
  sources: MonitorSource[];
}

const INTERVAL_OPTIONS = ['1h', '3h', '6h', '12h', '24h'];

const ZONE_COLORS = [
  'var(--color-accent)',
  'var(--color-info)',
  'var(--color-success)',
  'var(--color-warning)',
  'var(--color-danger)',
  'var(--color-danger)',
  'var(--color-accent)',
];

const INITIAL_ZONES: MonitorZone[] = [
  {
    id: 'AOI-001',
    name: '여수항 반경',
    interval: '6h',
    lastCheck: '03-16 14:00',
    status: '정상',
    alerts: 0,
    monitoring: true,
    color: 'var(--color-info)',
    polygon: [
      [127.68, 34.78],
      [127.78, 34.78],
      [127.78, 34.7],
      [127.68, 34.7],
    ],
    sources: ['satellite', 'cctv', 'ais'],
  },
  {
    id: 'AOI-002',
    name: '제주 서귀포 해상',
    interval: '3h',
    lastCheck: '03-16 13:30',
    status: '경보',
    alerts: 2,
    monitoring: true,
    color: 'var(--color-danger)',
    polygon: [
      [126.45, 33.28],
      [126.58, 33.28],
      [126.58, 33.2],
      [126.45, 33.2],
    ],
    sources: ['satellite', 'drone', 'cctv', 'ais'],
  },
  {
    id: 'AOI-003',
    name: '부산항 외항',
    interval: '12h',
    lastCheck: '03-16 08:00',
    status: '정상',
    alerts: 0,
    monitoring: true,
    color: 'var(--color-success)',
    polygon: [
      [129.05, 35.12],
      [129.2, 35.12],
      [129.2, 35.05],
      [129.05, 35.05],
    ],
    sources: ['cctv', 'ais'],
  },
  {
    id: 'AOI-004',
    name: '통영 ~ 거제 해역',
    interval: '24h',
    lastCheck: '03-15 20:00',
    status: '주의',
    alerts: 1,
    monitoring: true,
    color: 'var(--color-warning)',
    polygon: [
      [128.3, 34.9],
      [128.65, 34.9],
      [128.65, 34.8],
      [128.3, 34.8],
    ],
    sources: ['satellite', 'drone'],
  },
];

function AoiPanel() {
  const [zones, setZones] = useState<MonitorZone[]>(INITIAL_ZONES);
  const [selectedZone, setSelectedZone] = useState<string | null>(null);
  const currentMapStyle = useBaseMapStyle();
  const mapToggles = useMapStore((s) => s.mapToggles);
  // 드로잉 상태
  const [isDrawing, setIsDrawing] = useState(false);
  const [drawingPoints, setDrawingPoints] = useState<[number, number][]>([]);
  // 등록 폼
  const [showForm, setShowForm] = useState(false);
  const [formName, setFormName] = useState('');
  // 실시간 시뮬
  const [now, setNow] = useState(() => new Date());

  // 시계 갱신 (1분마다)
  useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 60_000);
    return () => clearInterval(t);
  }, []);

  const nextId = useRef(zones.length + 1);

  // 지도 클릭 → 폴리곤 포인트 수집
  const handleMapClick = useCallback(
    (e: MapMouseEvent) => {
      if (!isDrawing) return;
      setDrawingPoints((prev) => [...prev, [e.lngLat.lng, e.lngLat.lat]]);
    },
    [isDrawing],
  );

  // 드로잉 시작
  const startDrawing = () => {
    setDrawingPoints([]);
    setIsDrawing(true);
    setShowForm(false);
    setSelectedZone(null);
  };

  // 드로잉 완료 → 폼 표시
  const finishDrawing = () => {
    if (drawingPoints.length < 3) return;
    setIsDrawing(false);
    setShowForm(true);
    setFormName('');
  };

  // 드로잉 취소
  const cancelDrawing = () => {
    setIsDrawing(false);
    setDrawingPoints([]);
    setShowForm(false);
  };

  // 구역 등록 (이름만 → 등록 후 설정)
  const registerZone = () => {
    if (!formName.trim() || drawingPoints.length < 3) return;
    const newId = `AOI-${String(nextId.current++).padStart(3, '0')}`;
    const newZone: MonitorZone = {
      id: newId,
      name: formName.trim(),
      interval: '6h',
      lastCheck: `${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`,
      status: '정상',
      alerts: 0,
      polygon: [...drawingPoints],
      color: ZONE_COLORS[zones.length % ZONE_COLORS.length],
      monitoring: true,
      sources: ['satellite', 'cctv'],
    };
    setZones((prev) => [...prev, newZone]);
    setDrawingPoints([]);
    setShowForm(false);
    setSelectedZone(newId);
  };

  // 구역 설정 변경
  const updateZone = (id: string, patch: Partial<MonitorZone>) => {
    setZones((prev) => prev.map((z) => (z.id === id ? { ...z, ...patch } : z)));
  };

  // 모니터링 소스 토글
  const toggleSource = (id: string, src: MonitorSource) => {
    setZones((prev) =>
      prev.map((z) => {
        if (z.id !== id) return z;
        const has = z.sources.includes(src);
        return { ...z, sources: has ? z.sources.filter((s) => s !== src) : [...z.sources, src] };
      }),
    );
  };

  // 모니터링 토글
  const toggleMonitoring = (id: string) => {
    setZones((prev) => prev.map((z) => (z.id === id ? { ...z, monitoring: !z.monitoring } : z)));
  };

  // 구역 삭제
  const removeZone = (id: string) => {
    setZones((prev) => prev.filter((z) => z.id !== id));
    if (selectedZone === id) setSelectedZone(null);
  };

  const statusStyle = (s: ZoneStatus) => {
    if (s === '경보')
      return {
        background: 'color-mix(in srgb, var(--color-danger) 12%, transparent)',
        color: 'var(--color-danger)',
        border: '1px solid color-mix(in srgb, var(--color-danger) 25%, transparent)',
      };
    if (s === '주의')
      return {
        background: 'color-mix(in srgb, var(--color-caution) 12%, transparent)',
        color: 'var(--color-caution)',
        border: '1px solid color-mix(in srgb, var(--color-caution) 25%, transparent)',
      };
    return {
      background: 'color-mix(in srgb, var(--color-success) 12%, transparent)',
      color: 'var(--color-success)',
      border: '1px solid color-mix(in srgb, var(--color-success) 25%, transparent)',
    };
  };

  // deck.gl 레이어: 등록된 폴리곤 + 드로잉 중 포인트
  const deckLayers = useMemo(() => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const result: any[] = [];

    // 등록된 구역 폴리곤
    const visibleZones = zones.filter((z) => z.monitoring);
    if (visibleZones.length > 0) {
      result.push(
        new PolygonLayer({
          id: 'aoi-zones',
          data: visibleZones,
          getPolygon: (d: MonitorZone) => [...d.polygon, d.polygon[0]],
          getFillColor: (d: MonitorZone) => {
            const hex = d.color;
            const r = parseInt(hex.slice(1, 3), 16);
            const g = parseInt(hex.slice(3, 5), 16);
            const b = parseInt(hex.slice(5, 7), 16);
            const alpha = selectedZone === d.id ? 60 : 30;
            return [r, g, b, alpha];
          },
          getLineColor: (d: MonitorZone) => {
            const hex = d.color;
            const r = parseInt(hex.slice(1, 3), 16);
            const g = parseInt(hex.slice(3, 5), 16);
            const b = parseInt(hex.slice(5, 7), 16);
            return [r, g, b, selectedZone === d.id ? 220 : 140];
          },
          getLineWidth: (d: MonitorZone) => (selectedZone === d.id ? 3 : 1.5),
          lineWidthUnits: 'pixels',
          pickable: true,
          onClick: ({ object }: { object: MonitorZone }) => {
            if (object && !isDrawing)
              setSelectedZone(object.id === selectedZone ? null : object.id);
          },
          updateTriggers: {
            getFillColor: [selectedZone],
            getLineColor: [selectedZone],
            getLineWidth: [selectedZone],
          },
        }),
      );

      // 경보/주의 구역 중심점 펄스
      const alertZones = visibleZones.filter((z) => z.status !== '정상');
      if (alertZones.length > 0) {
        result.push(
          new ScatterplotLayer({
            id: 'aoi-alert-pulse',
            data: alertZones,
            getPosition: (d: MonitorZone) => {
              const lngs = d.polygon.map((p) => p[0]);
              const lats = d.polygon.map((p) => p[1]);
              return [
                (Math.min(...lngs) + Math.max(...lngs)) / 2,
                (Math.min(...lats) + Math.max(...lats)) / 2,
              ];
            },
            getRadius: 8000,
            radiusUnits: 'meters' as const,
            getFillColor: (d: MonitorZone) =>
              d.status === '경보' ? [239, 68, 68, 80] : [234, 179, 8, 60],
            getLineColor: (d: MonitorZone) =>
              d.status === '경보' ? [239, 68, 68, 180] : [234, 179, 8, 150],
            lineWidthMinPixels: 2,
            stroked: true,
          }),
        );
      }
    }

    // 드로잉 중 포인트
    if (drawingPoints.length > 0) {
      result.push(
        new ScatterplotLayer({
          id: 'drawing-points',
          data: drawingPoints,
          getPosition: (d: [number, number]) => d,
          getRadius: 5,
          radiusUnits: 'pixels' as const,
          getFillColor: [6, 182, 212, 220],
          getLineColor: [255, 255, 255, 255],
          lineWidthMinPixels: 2,
          stroked: true,
        }),
      );

      // 드로잉 폴리곤 미리보기
      if (drawingPoints.length >= 3) {
        result.push(
          new PolygonLayer({
            id: 'drawing-preview',
            data: [{ polygon: [...drawingPoints, drawingPoints[0]] }],
            getPolygon: (d: { polygon: [number, number][] }) => d.polygon,
            getFillColor: [6, 182, 212, 25],
            getLineColor: [6, 182, 212, 200],
            getLineWidth: 2,
            lineWidthUnits: 'pixels',
            getDashArray: [4, 4],
          }),
        );
      }
    }

    return result;
  }, [zones, drawingPoints, selectedZone, isDrawing]);

  const activeMonitoring = zones.filter((z) => z.monitoring).length;
  const alertCount = zones.filter((z) => z.status === '경보').length;
  const warningCount = zones.filter((z) => z.status === '주의').length;
  const totalAlerts = zones.reduce((s, a) => s + a.alerts, 0);

  const inputCls = 'w-full px-2.5 py-1.5 rounded text-caption font-korean outline-none border';
  const inputStyle = {
    background: 'var(--bg-elevated)',
    borderColor: 'var(--stroke-default)',
    color: 'var(--fg-default)',
  };

  return (
    <div>
      {/* 통계 */}
      <div className="grid grid-cols-4 gap-3 mb-4">
        {[
          { value: String(activeMonitoring), label: '감시 구역', color: 'var(--color-info)' },
          { value: String(alertCount), label: '경보', color: 'var(--color-danger)' },
          { value: String(warningCount), label: '주의', color: 'var(--color-caution)' },
          { value: String(totalAlerts), label: '미확인 알림', color: 'var(--color-tertiary)' },
        ].map((s, i) => (
          <div key={i} className="bg-bg-elevated border border-stroke rounded-md p-3 text-center">
            <div className="text-[20px] font-bold font-mono text-fg">{s.value}</div>
            <div className="text-caption text-fg-disabled mt-0.5 font-korean">{s.label}</div>
          </div>
        ))}
      </div>

      <div className="grid grid-cols-[1fr_360px] gap-4">
        {/* 지도 영역 */}
        <div
          className="bg-bg-elevated border border-stroke rounded-md overflow-hidden"
          style={{ minHeight: 520 }}
        >
          {/* 지도 헤더 */}
          <div className="flex items-center justify-between px-4 py-2.5 border-b border-stroke">
            <div className="flex items-center gap-2">
              <div className="text-label-2 font-bold font-korean text-fg">📍 연안 감시 구역</div>
              {isDrawing && (
                <span
                  className="text-caption px-1.5 py-0.5 rounded font-bold animate-pulse"
                  style={{
                    background: 'rgba(6,182,212,.12)',
                    color: 'var(--color-accent)',
                    border: '1px solid rgba(6,182,212,.3)',
                  }}
                >
                  드로잉 모드 · 지도를 클릭하여 꼭짓점 추가 ({drawingPoints.length}점)
                </span>
              )}
            </div>
            <div className="flex gap-1.5">
              {isDrawing ? (
                <>
                  <button
                    onClick={finishDrawing}
                    disabled={drawingPoints.length < 3}
                    className="px-2.5 h-6 text-color-accent rounded-sm text-caption font-semibold cursor-pointer font-korean disabled:opacity-40 disabled:cursor-not-allowed"
                    style={{
                      background: drawingPoints.length >= 3 ? 'rgba(6,182,212,0.08)' : '#333',
                    }}
                  >
                    완료 ({drawingPoints.length >= 3 ? `${drawingPoints.length}점` : '3점 이상'})
                  </button>
                  <button
                    onClick={() => setDrawingPoints((p) => p.slice(0, -1))}
                    disabled={drawingPoints.length === 0}
                    className="px-2 h-6 rounded-sm text-caption font-semibold cursor-pointer font-korean border disabled:opacity-40"
                    style={{
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--fg-sub)',
                    }}
                  >
                    되돌리기
                  </button>
                  <button
                    onClick={cancelDrawing}
                    className="px-2 h-6 rounded-sm text-caption font-semibold cursor-pointer font-korean border"
                    style={{
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--color-danger)',
                    }}
                  >
                    취소
                  </button>
                </>
              ) : (
                <button
                  onClick={startDrawing}
                  className="px-2.5 h-6 text-color-accent rounded-sm text-caption font-semibold cursor-pointer font-korean flex items-center gap-1"
                  style={{ background: 'rgba(6,182,212,0.08)' }}
                >
                  + 감시 구역 등록
                </button>
              )}
            </div>
          </div>

          {/* MapLibre 지도 */}
          <div style={{ height: 480, cursor: isDrawing ? 'crosshair' : undefined }}>
            <Map
              initialViewState={{ longitude: 127.8, latitude: 34.5, zoom: 6.5 }}
              style={{ width: '100%', height: '100%' }}
              mapStyle={currentMapStyle}
              attributionControl={false}
              onClick={handleMapClick}
            >
              <S57EncOverlay visible={mapToggles['s57'] ?? false} />
              <DeckGLOverlay layers={deckLayers} />
            </Map>
          </div>
        </div>

        {/* 우측 패널 */}
        <div
          className="flex flex-col gap-3"
          style={{
            maxHeight: 520,
            overflowY: 'scroll',
            scrollbarWidth: 'thin',
            scrollbarColor: 'var(--stroke-default) transparent',
          }}
        >
          {/* 등록 폼: 이름만 입력 → 바로 등록 */}
          {showForm && drawingPoints.length >= 3 && (
            <div
              className="bg-bg-elevated border rounded-md overflow-hidden"
              style={{ borderColor: 'rgba(6,182,212,.3)' }}
            >
              <div
                className="px-4 py-2.5 border-b font-korean"
                style={{ borderColor: 'rgba(6,182,212,.15)', background: 'rgba(6,182,212,.05)' }}
              >
                <div className="text-label-2 font-bold" style={{ color: 'var(--color-accent)' }}>
                  새 감시 구역 등록
                </div>
                <div className="text-caption text-fg-disabled mt-0.5">
                  폴리곤 {drawingPoints.length}점 설정 완료
                </div>
              </div>
              <div className="px-4 py-3">
                <label className="text-caption font-bold text-fg-disabled font-korean block mb-1.5">
                  구역 이름
                </label>
                <input
                  value={formName}
                  onChange={(e) => setFormName(e.target.value)}
                  placeholder="예: 여수항 북측 해안"
                  className={inputCls}
                  style={inputStyle}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter') registerZone();
                  }}
                  autoFocus
                />
                <div className="flex gap-2 mt-3">
                  <button
                    onClick={registerZone}
                    disabled={!formName.trim()}
                    className="flex-1 py-2 text-color-accent rounded text-caption font-bold cursor-pointer font-korean disabled:opacity-40 disabled:cursor-not-allowed"
                    style={{
                      background: formName.trim() ? 'rgba(6,182,212,0.08)' : '#333',
                    }}
                  >
                    등록
                  </button>
                  <button
                    onClick={cancelDrawing}
                    className="px-4 py-2 rounded text-caption font-bold cursor-pointer font-korean border"
                    style={{
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--fg-sub)',
                    }}
                  >
                    취소
                  </button>
                </div>
              </div>
            </div>
          )}

          {/* 감시 구역 목록 */}
          <div className="bg-bg-elevated border border-stroke rounded-md flex-1">
            <div className="flex items-center justify-between px-4 py-2.5 border-b border-stroke">
              <div className="text-label-2 font-bold font-korean text-fg">📋 등록된 감시 구역</div>
              <div className="text-caption text-fg-disabled font-mono">{zones.length}건</div>
            </div>
            <div className="divide-y divide-stroke">
              {zones.map((z) => {
                const isOpen = selectedZone === z.id;
                return (
                  <div key={z.id} className="border-b border-stroke last:border-b-0">
                    {/* 목록 행 */}
                    <div
                      onClick={() => setSelectedZone(isOpen ? null : z.id)}
                      className="px-4 py-2.5 hover:bg-bg-surface-hover/30 transition-colors cursor-pointer"
                      style={{ background: isOpen ? 'rgba(6,182,212,.04)' : undefined }}
                    >
                      <div className="flex items-center justify-between mb-1">
                        <div className="flex items-center gap-2">
                          <span className="text-caption font-mono text-fg-disabled">{z.id}</span>
                          <span className="text-label-2 font-semibold text-fg font-korean">
                            {z.name}
                          </span>
                        </div>
                        <div className="flex items-center gap-1.5">
                          <span
                            className="px-1.5 py-0.5 rounded text-caption font-bold font-korean"
                            style={statusStyle(z.status)}
                          >
                            {z.status}
                          </span>
                          <span className="text-caption text-fg-disabled">
                            {isOpen ? '▲' : '▼'}
                          </span>
                        </div>
                      </div>
                      {/* 활성 소스 배지 + 주기 */}
                      <div className="flex items-center gap-1.5 mt-1">
                        {z.sources.map((sid) => {
                          const cfg = MONITOR_SOURCES.find((s) => s.id === sid)!;
                          return (
                            <span
                              key={sid}
                              className="px-1.5 py-0.5 rounded text-caption font-bold"
                              style={{
                                background: 'transparent',
                                color: cfg.color,
                                border: `1px solid color-mix(in srgb, ${cfg.color} 40%, transparent)`,
                              }}
                            >
                              {cfg.label}
                            </span>
                          );
                        })}
                        <span className="text-caption text-fg-disabled font-mono ml-auto">
                          {z.interval} · {z.lastCheck}
                        </span>
                      </div>
                      {z.alerts > 0 && (
                        <div
                          className="mt-1.5 px-2 py-1 rounded text-caption font-bold font-korean"
                          style={{
                            background: 'color-mix(in srgb, var(--color-danger) 8%, transparent)',
                            color: 'var(--color-danger)',
                          }}
                        >
                          미확인 알림 {z.alerts}건
                        </div>
                      )}
                    </div>

                    {/* 인라인 설정 패널 (아코디언) */}
                    {isOpen && (
                      <div
                        className="px-4 py-3 space-y-3 border-t"
                        style={{
                          borderColor: `color-mix(in srgb, ${z.color} 12%, transparent)`,
                          background: `color-mix(in srgb, ${z.color} 3%, transparent)`,
                        }}
                      >
                        {/* 감시 주기 */}
                        <div>
                          <label className="text-caption font-bold text-fg-disabled font-korean block mb-1.5">
                            감시 주기
                          </label>
                          <div className="flex gap-1">
                            {INTERVAL_OPTIONS.map((iv) => (
                              <button
                                key={iv}
                                onClick={(e) => {
                                  e.stopPropagation();
                                  updateZone(z.id, { interval: iv });
                                }}
                                className="px-2.5 py-1 rounded text-caption font-bold font-mono cursor-pointer border transition-colors"
                                style={
                                  z.interval === iv
                                    ? {
                                        background: 'rgba(6,182,212,.08)',
                                        borderColor: 'rgba(6,182,212,.3)',
                                        color: 'var(--color-accent)',
                                      }
                                    : {
                                        background: 'var(--bg-card)',
                                        borderColor: 'var(--stroke-default)',
                                        color: 'var(--fg-disabled)',
                                      }
                                }
                              >
                                {iv}
                              </button>
                            ))}
                          </div>
                        </div>

                        {/* 모니터링 방법 */}
                        <div>
                          <label className="text-caption font-bold text-fg-disabled font-korean block mb-1.5">
                            모니터링 방법
                          </label>
                          <div className="space-y-1.5">
                            {MONITOR_SOURCES.map((src) => {
                              const active = z.sources.includes(src.id);
                              return (
                                <button
                                  key={src.id}
                                  onClick={(e) => {
                                    e.stopPropagation();
                                    toggleSource(z.id, src.id);
                                  }}
                                  className="w-full flex items-center gap-2.5 px-3 py-2 rounded border cursor-pointer transition-all text-left"
                                  style={
                                    active
                                      ? {
                                          background: 'transparent',
                                          borderColor: `color-mix(in srgb, ${src.color} 40%, transparent)`,
                                          color: 'var(--fg-default)',
                                        }
                                      : {
                                          background: 'var(--bg-card)',
                                          borderColor: 'var(--stroke-default)',
                                          color: 'var(--fg-disabled)',
                                          opacity: 0.6,
                                        }
                                  }
                                >
                                  <span className="text-body-2 shrink-0">{active ? '◉' : '○'}</span>
                                  <span className="text-body-2 shrink-0">{src.icon}</span>
                                  <div className="flex-1 min-w-0">
                                    <div className="text-caption font-bold font-korean">
                                      {src.label}
                                    </div>
                                    <div className="text-caption font-korean text-fg-disabled">
                                      {src.desc}
                                    </div>
                                  </div>
                                </button>
                              );
                            })}
                          </div>
                          {z.sources.length === 0 && (
                            <div className="text-caption text-fg-disabled font-korean mt-1.5">
                              최소 1개 이상의 모니터링 방법을 선택하세요
                            </div>
                          )}
                        </div>

                        {/* 하단 컨트롤 */}
                        <div
                          className="flex items-center gap-2 pt-1 border-t"
                          style={{ borderColor: 'var(--stroke-default)' }}
                        >
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              toggleMonitoring(z.id);
                            }}
                            className="px-3 py-1.5 rounded text-caption font-bold font-korean cursor-pointer border transition-colors"
                            style={
                              z.monitoring
                                ? {
                                    background:
                                      'color-mix(in srgb, var(--color-success) 12%, transparent)',
                                    borderColor:
                                      'color-mix(in srgb, var(--color-success) 25%, transparent)',
                                    color: 'var(--color-success)',
                                  }
                                : {
                                    background: 'var(--bg-card)',
                                    borderColor: 'var(--stroke-default)',
                                    color: 'var(--fg-disabled)',
                                  }
                            }
                          >
                            {z.monitoring ? '◉ 감시 중' : '○ 일시정지'}
                          </button>
                          <span className="text-caption text-fg-disabled font-mono">
                            {z.polygon.length}점 · {z.sources.length}소스 · {z.interval}
                          </span>
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              removeZone(z.id);
                            }}
                            className="ml-auto px-2 py-1.5 rounded text-caption font-bold font-korean cursor-pointer border"
                            style={{
                              background: 'color-mix(in srgb, var(--color-danger) 8%, transparent)',
                              borderColor:
                                'color-mix(in srgb, var(--color-danger) 20%, transparent)',
                              color: 'var(--color-danger)',
                            }}
                          >
                            삭제
                          </button>
                        </div>
                      </div>
                    )}
                  </div>
                );
              })}
              {zones.length === 0 && (
                <div className="px-4 py-8 text-center">
                  <div className="text-2xl opacity-30 mb-2">📍</div>
                  <div className="text-caption text-fg-disabled font-korean">
                    등록된 감시 구역이 없습니다
                  </div>
                  <div className="text-caption text-fg-disabled font-korean mt-1">
                    "+ 감시 구역 등록" 버튼으로 시작하세요
                  </div>
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
