import { useState, useCallback, useEffect, useRef } from 'react';
import { Map, Marker, Popup } from '@vis.gl/react-maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';
import { fetchCctvCameras } from '../services/aerialApi';
import { useBaseMapStyle } from '@common/hooks/useBaseMapStyle';
import { S57EncOverlay } from '@common/components/map/S57EncOverlay';
import { useMapStore } from '@common/store/mapStore';
import type { CctvCameraItem } from '../services/aerialApi';
import { CCTVPlayer } from './CCTVPlayer';
import type { CCTVPlayerHandle } from './CCTVPlayer';

/** KHOA HLS 스트림 베이스 URL */
const KHOA_HLS = 'https://www.khoa.go.kr/SEAFOG/m4NiLawsC202gM5ixA7MPTYtO19KmV/hls/khoa';

/** KHOA HLS 스트림 URL 생성 */
function khoaHlsUrl(siteName: string): string {
  return `${KHOA_HLS}/${siteName}/s.m3u8`;
}

/** KBS 재난안전포탈 CCTV — 백엔드 HLS 리졸버 경유 */
function kbsCctvUrl(cctvId: number): string {
  return `/api/aerial/cctv/kbs-hls/${cctvId}/stream.m3u8`;
}

const cctvFavorites = [
  { name: '여수항 해무관측', reason: '유출 사고 인접' },
  { name: '부산항 조위관측소', reason: '주요 방제 거점' },
  { name: '목포항 해무관측', reason: '서해 모니터링' },
];

/** badatime.com 실제 해안 CCTV 데이터 (API 미연결 시 폴백) */
const FALLBACK_CAMERAS: CctvCameraItem[] = [
  // 서해
  {
    cctvSn: 29,
    cameraNm: '인천항 조위관측소',
    regionNm: '서해',
    lon: 126.5922,
    lat: 37.4519,
    locDc: '인천광역시 중구 항동',
    coordDc: '37.45°N 126.59°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('Incheon'),
  },
  {
    cctvSn: 30,
    cameraNm: '인천항 해무관측',
    regionNm: '서해',
    lon: 126.6161,
    lat: 37.3797,
    locDc: '인천광역시 중구 항동',
    coordDc: 'N 37°22\'47" E 126°36\'58"',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Incheon'),
  },
  {
    cctvSn: 31,
    cameraNm: '대산항 해무관측',
    regionNm: '서해',
    lon: 126.3526,
    lat: 37.0058,
    locDc: '충남 서산시 대산읍',
    coordDc: '37.01°N 126.35°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Daesan'),
  },
  {
    cctvSn: 32,
    cameraNm: '평택·당진항 해무관측',
    regionNm: '서해',
    lon: 126.3936,
    lat: 37.1131,
    locDc: '충남 당진시 송악읍',
    coordDc: 'N 37°06\'47" E 126°23\'37"',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_PTDJ'),
  },
  {
    cctvSn: 100,
    cameraNm: '인천 연안부두',
    regionNm: '서해',
    lon: 126.5986,
    lat: 37.4541,
    locDc: '인천광역시 중구 연안부두',
    coordDc: '37.45°N 126.60°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9981),
  },
  {
    cctvSn: 200,
    cameraNm: '연평도',
    regionNm: '서해',
    lon: 125.6945,
    lat: 37.662,
    locDc: '인천 옹진군 연평면',
    coordDc: '37.66°N 125.69°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9958),
  },
  {
    cctvSn: 201,
    cameraNm: '군산 비응항',
    regionNm: '서해',
    lon: 126.5265,
    lat: 35.9353,
    locDc: '전북 군산시 비응도동',
    coordDc: '35.94°N 126.53°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9979),
  },
  {
    cctvSn: 202,
    cameraNm: '태안 신진항',
    regionNm: '서해',
    lon: 126.1365,
    lat: 36.6779,
    locDc: '충남 태안군 근흥면',
    coordDc: '36.68°N 126.14°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9980),
  },
  // 남해
  {
    cctvSn: 35,
    cameraNm: '목포항 해무관측',
    regionNm: '남해',
    lon: 126.378,
    lat: 34.778,
    locDc: '전남 목포시 항동',
    coordDc: '34.78°N 126.38°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Mokpo'),
  },
  {
    cctvSn: 36,
    cameraNm: '진도항 조위관측소',
    regionNm: '남해',
    lon: 126.3085,
    lat: 34.471,
    locDc: '전남 진도군 진도읍',
    coordDc: '34.47°N 126.31°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('Jindo'),
  },
  {
    cctvSn: 37,
    cameraNm: '여수항 해무관측',
    regionNm: '남해',
    lon: 127.7669,
    lat: 34.7384,
    locDc: '전남 여수시 종화동',
    coordDc: '34.74°N 127.77°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Yeosu'),
  },
  {
    cctvSn: 38,
    cameraNm: '여수항 조위관측소',
    regionNm: '남해',
    lon: 127.765,
    lat: 34.737,
    locDc: '전남 여수시 종화동',
    coordDc: '34.74°N 127.77°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('Yeosu'),
  },
  {
    cctvSn: 39,
    cameraNm: '부산항 조위관측소',
    regionNm: '남해',
    lon: 129.0756,
    lat: 35.0969,
    locDc: '부산광역시 중구 중앙동',
    coordDc: '35.10°N 129.08°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('Busan'),
  },
  {
    cctvSn: 40,
    cameraNm: '부산항 해무관측',
    regionNm: '남해',
    lon: 129.078,
    lat: 35.098,
    locDc: '부산광역시 중구',
    coordDc: '35.10°N 129.08°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Busan'),
  },
  {
    cctvSn: 41,
    cameraNm: '해운대 해무관측',
    regionNm: '남해',
    lon: 129.1718,
    lat: 35.1587,
    locDc: '부산광역시 해운대구',
    coordDc: '35.16°N 129.17°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Haeundae'),
  },
  {
    cctvSn: 97,
    cameraNm: '여수 오동도 앞',
    regionNm: '남해',
    lon: 127.7557,
    lat: 34.741,
    locDc: '전남 여수시 수정동',
    coordDc: '34.74°N 127.76°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9994),
  },
  {
    cctvSn: 108,
    cameraNm: '완도항',
    regionNm: '남해',
    lon: 126.7489,
    lat: 34.3209,
    locDc: '전남 완도군 완도읍',
    coordDc: '34.32°N 126.75°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9984),
  },
  {
    cctvSn: 203,
    cameraNm: '창원 마산항',
    regionNm: '남해',
    lon: 128.576,
    lat: 35.1979,
    locDc: '경남 창원시 마산합포구',
    coordDc: '35.20°N 128.58°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9985),
  },
  {
    cctvSn: 204,
    cameraNm: '부산 민락항',
    regionNm: '남해',
    lon: 129.1312,
    lat: 35.1538,
    locDc: '부산 수영구 민락동',
    coordDc: '35.15°N 129.13°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9991),
  },
  {
    cctvSn: 205,
    cameraNm: '목포 북항',
    regionNm: '남해',
    lon: 126.3652,
    lat: 34.8042,
    locDc: '전남 목포시 죽교동',
    coordDc: '34.80°N 126.37°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9992),
  },
  {
    cctvSn: 206,
    cameraNm: '신안 가거도',
    regionNm: '남해',
    lon: 125.1293,
    lat: 34.0529,
    locDc: '전남 신안군 흑산면',
    coordDc: '34.05°N 125.13°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9983),
  },
  {
    cctvSn: 207,
    cameraNm: '여수 거문도',
    regionNm: '남해',
    lon: 127.3074,
    lat: 34.0232,
    locDc: '전남 여수시 삼산면',
    coordDc: '34.02°N 127.31°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9993),
  },
  // 동해
  {
    cctvSn: 42,
    cameraNm: '울산항 해무관측',
    regionNm: '동해',
    lon: 129.387,
    lat: 35.5,
    locDc: '울산광역시 남구',
    coordDc: '35.50°N 129.39°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Ulsan'),
  },
  {
    cctvSn: 43,
    cameraNm: '포항항 해무관측',
    regionNm: '동해',
    lon: 129.3798,
    lat: 36.0323,
    locDc: '경북 포항시 북구',
    coordDc: '36.03°N 129.38°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('SeaFog_Pohang'),
  },
  {
    cctvSn: 44,
    cameraNm: '묵호항 조위관측소',
    regionNm: '동해',
    lon: 129.1146,
    lat: 37.55,
    locDc: '강원 동해시 묵호동',
    coordDc: '37.55°N 129.11°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('Mukho'),
  },
  {
    cctvSn: 113,
    cameraNm: '속초 등대전망대',
    regionNm: '동해',
    lon: 128.6001,
    lat: 38.2134,
    locDc: '강원 속초시 영랑동',
    coordDc: '38.21°N 128.60°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9986),
  },
  {
    cctvSn: 115,
    cameraNm: '독도',
    regionNm: '동해',
    lon: 131.8686,
    lat: 37.2394,
    locDc: '경북 울릉군 울릉읍 독도리',
    coordDc: '37.24°N 131.87°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9957),
  },
  {
    cctvSn: 208,
    cameraNm: '강릉 용강동',
    regionNm: '동해',
    lon: 128.8912,
    lat: 37.7521,
    locDc: '강원 강릉시 용강동',
    coordDc: '37.75°N 128.89°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9952),
  },
  {
    cctvSn: 209,
    cameraNm: '강릉 주문진방파제',
    regionNm: '동해',
    lon: 128.8335,
    lat: 37.8934,
    locDc: '강원 강릉시 주문진읍',
    coordDc: '37.89°N 128.83°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9995),
  },
  {
    cctvSn: 210,
    cameraNm: '대관령',
    regionNm: '동해',
    lon: 128.7553,
    lat: 37.698,
    locDc: '강원 평창군 대관령면',
    coordDc: '37.70°N 128.76°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9989),
  },
  {
    cctvSn: 211,
    cameraNm: '울릉 저동항',
    regionNm: '동해',
    lon: 130.9122,
    lat: 37.4913,
    locDc: '경북 울릉군 울릉읍',
    coordDc: '37.49°N 130.91°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9987),
  },
  {
    cctvSn: 212,
    cameraNm: '포항 두호동 해안로',
    regionNm: '동해',
    lon: 129.3896,
    lat: 36.0627,
    locDc: '경북 포항시 북구 두호동',
    coordDc: '36.06°N 129.39°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9988),
  },
  {
    cctvSn: 213,
    cameraNm: '울산 달동',
    regionNm: '동해',
    lon: 129.3265,
    lat: 35.5442,
    locDc: '울산 남구 달동',
    coordDc: '35.54°N 129.33°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9955),
  },
  // 제주
  {
    cctvSn: 45,
    cameraNm: '모슬포항 조위관측소',
    regionNm: '제주',
    lon: 126.2519,
    lat: 33.2136,
    locDc: '제주 서귀포시 대정읍',
    coordDc: '33.21°N 126.25°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KHOA',
    streamUrl: khoaHlsUrl('Moseulpo'),
  },
  {
    cctvSn: 116,
    cameraNm: '마라도',
    regionNm: '제주',
    lon: 126.2684,
    lat: 33.1139,
    locDc: '제주 서귀포시 대정읍 마라리',
    coordDc: '33.11°N 126.27°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9982),
  },
  {
    cctvSn: 214,
    cameraNm: '제주 도남동',
    regionNm: '제주',
    lon: 126.5195,
    lat: 33.4891,
    locDc: '제주시 도남동',
    coordDc: '33.49°N 126.52°E',
    sttsCd: 'LIVE',
    ptzYn: 'N',
    sourceNm: 'KBS',
    streamUrl: kbsCctvUrl(9954),
  },
];

export function CctvView() {
  const [cameras, setCameras] = useState<CctvCameraItem[]>([]);
  const [loading, setLoading] = useState(true);
  const [searchTerm, setSearchTerm] = useState('');
  const [regionFilter, setRegionFilter] = useState('전체');
  const [selectedCamera, setSelectedCamera] = useState<CctvCameraItem | null>(null);
  const [gridMode, setGridMode] = useState(1);
  const [activeCells, setActiveCells] = useState<CctvCameraItem[]>([]);
  const [oilDetectionEnabled, setOilDetectionEnabled] = useState(false);
  const [vesselDetectionEnabled, setVesselDetectionEnabled] = useState(false);
  const [intrusionDetectionEnabled, setIntrusionDetectionEnabled] = useState(false);
  const [mapPopup, setMapPopup] = useState<CctvCameraItem | null>(null);
  const [viewMode, setViewMode] = useState<'list' | 'map'>('map');
  const playerRefs = useRef<(CCTVPlayerHandle | null)[]>([]);
  const currentMapStyle = useBaseMapStyle();
  const mapToggles = useMapStore((s) => s.mapToggles);

  /** 지도 모드이거나, 리스트 모드에서 카메라 미선택 시 지도 표시 */
  const showMap = viewMode === 'map' && activeCells.length === 0;

  const loadData = useCallback(async () => {
    setLoading(true);
    try {
      const items = await fetchCctvCameras();
      if (items.length > 0) {
        // DB 데이터에 폴백 전용 카메라(DB 미등록분) 병합
        const dbIds = new Set(items.map((i) => i.cctvSn));
        const missing = FALLBACK_CAMERAS.filter((f) => !dbIds.has(f.cctvSn));
        setCameras([...items, ...missing]);
      } else {
        setCameras(FALLBACK_CAMERAS);
      }
    } catch {
      setCameras(FALLBACK_CAMERAS);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    loadData();
  }, [loadData]);

  const regions = ['전체', '제주', '남해', '서해', '동해'];
  const regionIcons: Record<string, string> = {
    전체: '',
    제주: '🌊',
    남해: '⚓',
    서해: '🐟',
    동해: '🌅',
  };

  const filtered = cameras.filter((c) => {
    if (regionFilter !== '전체' && c.regionNm !== regionFilter) return false;
    if (searchTerm && !c.cameraNm.includes(searchTerm) && !(c.locDc ?? '').includes(searchTerm))
      return false;
    return true;
  });

  const handleSelectCamera = (cam: CctvCameraItem) => {
    setSelectedCamera(cam);
    if (gridMode === 1) {
      setActiveCells([cam]);
    } else {
      setActiveCells((prev) => {
        if (prev.length < gridMode && !prev.find((c) => c.cctvSn === cam.cctvSn))
          return [...prev, cam];
        return prev;
      });
    }
  };

  const gridCols = gridMode === 1 ? 1 : gridMode === 4 ? 2 : 3;
  const totalCells = gridMode;

  return (
    <div
      className="flex h-full overflow-hidden"
      style={{ margin: '-20px -24px', height: 'calc(100% + 40px)' }}
    >
      {/* 왼쪽: 목록 패널 */}
      <div className="flex flex-col overflow-hidden bg-bg-surface border-r border-stroke w-[290px] min-w-[290px]">
        {/* 헤더 */}
        <div className="p-3 pb-2.5 border-b border-stroke shrink-0 bg-bg-elevated">
          <div className="flex items-center justify-between mb-2">
            <div className="text-xs font-bold text-fg font-korean flex items-center gap-1.5">
              <span
                className="w-[7px] h-[7px] rounded-full inline-block animate-pulse"
                style={{ background: 'var(--color-danger)' }}
              />
              실시간 해안 CCTV
            </div>
            <div className="flex items-center gap-1">
              {/* 지도/리스트 뷰 토글 */}
              <div className="flex border border-stroke rounded-[5px] overflow-hidden mr-1.5">
                {/* <button
                  onClick={() => setViewMode('map')}
                  className="px-1.5 py-0.5 text-caption font-semibold cursor-pointer border-none font-korean transition-colors"
                  style={
                    viewMode === 'map'
                      ? { background: 'rgba(6,182,212,.15)', color: 'var(--color-accent)' }
                      : { background: 'var(--bg-card)', color: 'var(--fg-disabled)' }
                  }
                  title="지도 보기"
                >
                  🗺 지도
                </button> */}
                {/* <button
                  onClick={() => setViewMode('list')}
                  className="px-1.5 py-0.5 text-caption font-semibold cursor-pointer border-none font-korean transition-colors"
                  style={
                    viewMode === 'list'
                      ? { background: 'rgba(6,182,212,.15)', color: 'var(--color-accent)' }
                      : { background: 'var(--bg-card)', color: 'var(--fg-disabled)' }
                  }
                  title="리스트 보기"
                >
                  ☰ 리스트
                </button> */}
              </div>
              <span className="text-caption text-fg-disabled font-korean">API</span>
              <span
                className="w-[7px] h-[7px] rounded-full inline-block"
                style={{ background: 'var(--color-success)' }}
              />
            </div>
          </div>
          {/* 검색 */}
          <div className="flex items-center gap-2 bg-bg-base border border-stroke rounded-md px-2.5 py-1.5 mb-2 focus-within:border-[rgba(6,182,212,0.5)] transition-colors">
            <span className="text-fg-disabled text-label-2">🔍</span>
            <input
              type="text"
              placeholder="지점명 또는 지역 검색..."
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              className="flex-1 bg-transparent border-none text-fg text-label-2 font-korean outline-none"
            />
          </div>
          {/* 지역 필터 */}
          <div className="flex gap-1 flex-wrap">
            {regions.map((r) => (
              <button
                key={r}
                onClick={() => setRegionFilter(r)}
                className="px-2 py-0.5 rounded text-caption font-semibold cursor-pointer font-korean border transition-colors"
                style={
                  regionFilter === r
                    ? {
                        background: 'rgba(6,182,212,.15)',
                        color: 'var(--color-accent)',
                        borderColor: 'rgba(6,182,212,.3)',
                      }
                    : {
                        background: 'var(--bg-card)',
                        color: 'var(--fg-sub)',
                        borderColor: 'var(--stroke-default)',
                      }
                }
              >
                {regionIcons[r] ? `${regionIcons[r]} ` : ''}
                {r}
              </button>
            ))}
          </div>
        </div>

        {/* 상태 바 */}
        <div className="flex items-center justify-between px-3.5 py-1 border-b border-stroke shrink-0 bg-bg-surface">
          <div className="text-caption text-fg-disabled font-korean">
            출처: 국립해양조사원 · KBS 재난안전포털
          </div>
          <div className="text-label-1 text-fg-sub font-korean">
            <b className="text-fg">{filtered.length}</b>개
          </div>
        </div>

        {/* 카메라 목록 */}
        <div
          className="flex-1 overflow-y-auto"
          style={{ scrollbarWidth: 'thin', scrollbarColor: 'var(--stroke-light) transparent' }}
        >
          {loading ? (
            <div className="px-3.5 py-4 text-label-2 text-fg-disabled font-korean">
              불러오는 중...
            </div>
          ) : (
            filtered.map((cam) => (
              <div
                key={cam.cctvSn}
                onClick={() => handleSelectCamera(cam)}
                className="flex items-center gap-2.5 px-3.5 py-2.5 border-b cursor-pointer transition-colors"
                style={{
                  borderColor: 'rgba(255,255,255,.04)',
                  background:
                    selectedCamera?.cctvSn === cam.cctvSn ? 'rgba(6,182,212,.08)' : 'transparent',
                }}
              >
                <div className="relative shrink-0">
                  <div className="w-8 h-8 rounded-md bg-bg-card flex items-center justify-center">
                    <svg width="18" height="18" viewBox="0 0 24 24" fill="none">
                      <rect
                        x="3"
                        y="6"
                        width="13"
                        height="10"
                        rx="2"
                        fill={cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)'}
                      />
                      <circle cx="9.5" cy="11" r="2.8" fill="var(--bg-card)" />
                      <circle
                        cx="9.5"
                        cy="11"
                        r="1.3"
                        fill={cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)'}
                      />
                      <path
                        d="M17 9l4-2v10l-4-2V9z"
                        fill={cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)'}
                        opacity="0.7"
                      />
                    </svg>
                  </div>
                  <div
                    className="absolute -top-0.5 -right-0.5 w-2 h-2 rounded-full border border-bg-1"
                    style={{
                      background:
                        cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)',
                    }}
                  />
                </div>
                <div className="flex-1 min-w-0">
                  <div className="text-label-2 font-semibold text-fg font-korean truncate">
                    {cam.cameraNm}
                  </div>
                  <div className="text-caption text-fg-disabled font-korean truncate">
                    {cam.locDc ?? ''}
                  </div>
                </div>
                <div className="flex flex-col items-end gap-0.5 shrink-0">
                  {cam.sttsCd === 'LIVE' ? (
                    <span
                      className="text-caption font-bold px-1.5 py-px rounded-full"
                      style={{
                        background: 'color-mix(in srgb, var(--color-success) 12%, transparent)',
                        color: 'var(--color-success)',
                      }}
                    >
                      LIVE
                    </span>
                  ) : (
                    <span
                      className="text-caption font-bold px-1.5 py-px rounded-full"
                      style={{ background: 'rgba(255,255,255,.06)', color: 'var(--fg-disabled)' }}
                    >
                      OFF
                    </span>
                  )}
                  {cam.ptzYn === 'Y' && (
                    <span className="text-caption text-fg-disabled font-mono">PTZ</span>
                  )}
                </div>
              </div>
            ))
          )}
        </div>
      </div>

      {/* 가운데: 영상 뷰어 */}
      <div className="flex-1 flex flex-col overflow-hidden min-w-0 bg-bg-base">
        {/* 뷰어 툴바 */}
        <div className="flex items-center justify-between px-4 py-2 border-b border-stroke bg-bg-elevated shrink-0 gap-2.5">
          <div className="flex items-center gap-2 min-w-0">
            <div className="text-xs font-bold text-fg font-korean whitespace-nowrap overflow-hidden text-ellipsis">
              {selectedCamera ? `📹 ${selectedCamera.cameraNm}` : '📹 카메라를 선택하세요'}
            </div>
            {selectedCamera?.sttsCd === 'LIVE' && (
              <div
                className="flex items-center gap-1 px-2 py-0.5 rounded-full text-caption font-bold shrink-0"
                style={{
                  background: 'color-mix(in srgb, var(--color-danger) 14%, transparent)',
                  border: '1px solid color-mix(in srgb, var(--color-danger) 35%, transparent)',
                  color: 'var(--color-danger)',
                }}
              >
                <span
                  className="w-[5px] h-[5px] rounded-full inline-block animate-pulse"
                  style={{ background: 'var(--color-danger)' }}
                />
                LIVE
              </div>
            )}
          </div>
          <div className="flex items-center gap-1.5 shrink-0">
            {/* PTZ 컨트롤 */}
            {selectedCamera?.ptzYn === 'Y' && (
              <div className="flex items-center gap-1 px-2 py-1 bg-bg-card border border-stroke rounded-[5px]">
                <span className="text-caption text-fg-disabled font-korean mr-1">PTZ</span>
                {['◀', '▲', '▼', '▶'].map((d, i) => (
                  <button
                    key={i}
                    className="w-5 h-5 flex items-center justify-center bg-bg-base border border-stroke rounded text-caption text-fg-sub cursor-pointer hover:bg-bg-surface-hover transition-colors"
                  >
                    {d}
                  </button>
                ))}
                <div className="w-px h-4 bg-border mx-0.5" />
                {['+', '−'].map((z, i) => (
                  <button
                    key={i}
                    className="w-5 h-5 flex items-center justify-center bg-bg-base border border-stroke rounded text-caption text-fg-sub cursor-pointer hover:bg-bg-surface-hover transition-colors"
                  >
                    {z}
                  </button>
                ))}
              </div>
            )}
            {/* 분할 모드 */}
            <div className="flex border border-stroke rounded-[5px] overflow-hidden">
              {[
                { mode: 1, icon: '▣', label: '1화면' },
                { mode: 4, icon: '⊞', label: '4분할' },
                { mode: 9, icon: '⊟', label: '9분할' },
              ].map((g) => (
                <button
                  key={g.mode}
                  onClick={() => {
                    setGridMode(g.mode);
                    setActiveCells((prev) => prev.slice(0, g.mode));
                  }}
                  title={g.label}
                  className="px-2 py-1 text-label-2 cursor-pointer border-none transition-colors"
                  style={
                    gridMode === g.mode
                      ? { background: 'rgba(6,182,212,.15)', color: 'var(--color-accent)' }
                      : { background: 'var(--bg-card)', color: 'var(--fg-sub)' }
                  }
                >
                  {g.icon}
                </button>
              ))}
            </div>
            <button
              onClick={() => setOilDetectionEnabled((v) => !v)}
              className="px-2.5 py-1 border rounded-[5px] text-label-1 font-semibold cursor-pointer font-korean transition-colors"
              style={
                oilDetectionEnabled
                  ? {
                      background: 'color-mix(in srgb, var(--color-danger) 15%, transparent)',
                      borderColor: 'color-mix(in srgb, var(--color-danger) 40%, transparent)',
                      color: 'var(--color-danger)',
                    }
                  : {
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--fg-sub)',
                    }
              }
              title={gridMode === 9 ? '9분할 모드에서는 비활성화됩니다' : '오일 유출 감지'}
            >
              {oilDetectionEnabled ? '🛢 감지 ON' : '🛢 오일 감지'}
            </button>
            <button
              onClick={() => setVesselDetectionEnabled((v) => !v)}
              className="px-2.5 py-1 border rounded-[5px] text-label-1 font-semibold cursor-pointer font-korean transition-colors"
              style={
                vesselDetectionEnabled
                  ? {
                      background: 'color-mix(in srgb, var(--color-info) 15%, transparent)',
                      borderColor: 'color-mix(in srgb, var(--color-info) 40%, transparent)',
                      color: 'var(--color-info)',
                    }
                  : {
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--fg-sub)',
                    }
              }
              title={gridMode === 9 ? '9분할 모드에서는 비활성화됩니다' : '선박 출입 감지'}
            >
              {vesselDetectionEnabled ? '🚢 감지 ON' : '🚢 선박 출입'}
            </button>
            <button
              onClick={() => setIntrusionDetectionEnabled((v) => !v)}
              className="px-2.5 py-1 border rounded-[5px] text-label-1 font-semibold cursor-pointer font-korean transition-colors"
              style={
                intrusionDetectionEnabled
                  ? {
                      background: 'color-mix(in srgb, var(--color-warning) 15%, transparent)',
                      borderColor: 'color-mix(in srgb, var(--color-warning) 40%, transparent)',
                      color: 'var(--color-warning)',
                    }
                  : {
                      background: 'var(--bg-card)',
                      borderColor: 'var(--stroke-default)',
                      color: 'var(--fg-sub)',
                    }
              }
              title={gridMode === 9 ? '9분할 모드에서는 비활성화됩니다' : '침입 감지'}
            >
              {intrusionDetectionEnabled ? '🚨 감지 ON' : '🚨 침입 감지'}
            </button>
            <button
              onClick={() => {
                playerRefs.current.forEach((r) => r?.capture());
              }}
              className="px-2.5 py-1 bg-bg-card border border-stroke rounded-[5px] text-fg-sub text-label-1 font-semibold cursor-pointer font-korean hover:bg-bg-surface-hover transition-colors"
            >
              📷 캡처
            </button>
          </div>
        </div>

        {/* 영상 그리드 / CCTV 위치 지도 / 리스트 뷰 */}
        {viewMode === 'list' && activeCells.length === 0 ? (
          /* ── 리스트 뷰: 출처별 · 지역별 그리드 ── */
          <div
            className="flex-1 overflow-y-auto p-4"
            style={{ scrollbarWidth: 'thin', scrollbarColor: 'var(--stroke-light) transparent' }}
          >
            {(() => {
              // 출처별 그룹핑
              const sourceGroups: Record<
                string,
                { label: string; icon: string; cameras: CctvCameraItem[] }
              > = {};
              for (const cam of filtered) {
                const src = cam.sourceNm ?? '기타';
                if (!sourceGroups[src]) {
                  sourceGroups[src] = {
                    label:
                      src === 'KHOA'
                        ? '국립해양조사원 (KHOA)'
                        : src === 'KBS'
                          ? 'KBS 재난안전포털'
                          : src,
                    icon: src === 'KHOA' ? '🌊' : src === 'KBS' ? '📡' : '📹',
                    cameras: [],
                  };
                }
                sourceGroups[src].cameras.push(cam);
              }
              const now = new Date().toLocaleString('ko-KR', {
                year: 'numeric',
                month: '2-digit',
                day: '2-digit',
                hour: '2-digit',
                minute: '2-digit',
              });

              return Object.entries(sourceGroups).map(([srcKey, group]) => {
                // 출처 내에서 지역별 그룹핑
                const regionGroups: Record<string, CctvCameraItem[]> = {};
                for (const cam of group.cameras) {
                  const rgn = cam.regionNm ?? '기타';
                  if (!regionGroups[rgn]) regionGroups[rgn] = [];
                  regionGroups[rgn].push(cam);
                }

                return (
                  <div key={srcKey} className="mb-5">
                    {/* 출처 헤더 */}
                    <div className="flex items-center gap-2 mb-2 pb-1.5 border-b border-stroke">
                      <span className="text-sm">{group.icon}</span>
                      <span className="text-label-1 font-bold text-fg font-korean">
                        {group.label}
                      </span>
                      <span className="text-label-1 text-fg-disabled font-korean ml-auto">
                        {group.cameras.length}개
                      </span>
                    </div>

                    {Object.entries(regionGroups).map(([rgn, cams]) => (
                      <div key={rgn} className="mb-3">
                        {/* 지역 소제목 */}
                        <div className="flex items-center gap-1.5 mb-1.5 px-1">
                          <span className="text-label-1 font-bold text-color-accent font-korean">
                            {rgn}
                          </span>
                          <span className="text-caption text-fg-disabled">({cams.length})</span>
                        </div>
                        {/* 테이블 헤더 */}
                        <div
                          className="grid px-2 py-1 bg-bg-card rounded-t text-caption font-bold text-fg-disabled font-korean border border-stroke"
                          style={{ gridTemplateColumns: '1fr 1.2fr 70px 130px' }}
                        >
                          <span>카메라명</span>
                          <span>위치</span>
                          <span className="text-center">상태</span>
                          <span className="text-center">최종갱신</span>
                        </div>
                        {/* 테이블 행 */}
                        {cams.map((cam) => (
                          <div
                            key={cam.cctvSn}
                            onClick={() => {
                              handleSelectCamera(cam);
                              setViewMode('map');
                            }}
                            className="grid px-2 py-1.5 border-b border-x border-stroke cursor-pointer transition-colors hover:bg-bg-surface-hover"
                            style={{
                              gridTemplateColumns: '1fr 1.2fr 70px 130px',
                              background:
                                selectedCamera?.cctvSn === cam.cctvSn
                                  ? 'rgba(6,182,212,.08)'
                                  : 'transparent',
                            }}
                          >
                            <span className="text-label-1 text-fg font-korean font-semibold truncate">
                              {cam.cameraNm}
                            </span>
                            <span className="text-caption text-fg-disabled font-korean truncate">
                              {cam.locDc ?? '—'}
                            </span>
                            <span className="text-center">
                              {cam.sttsCd === 'LIVE' ? (
                                <span
                                  className="text-caption font-bold px-1.5 py-px rounded-full inline-block"
                                  style={{
                                    background:
                                      'color-mix(in srgb, var(--color-success) 12%, transparent)',
                                    color: 'var(--color-success)',
                                  }}
                                >
                                  ● LIVE
                                </span>
                              ) : (
                                <span
                                  className="text-caption font-bold px-1.5 py-px rounded-full inline-block"
                                  style={{
                                    background: 'rgba(255,255,255,.06)',
                                    color: 'var(--fg-disabled)',
                                  }}
                                >
                                  ● OFF
                                </span>
                              )}
                            </span>
                            <span className="text-caption text-fg-disabled font-mono text-center">
                              {now}
                            </span>
                          </div>
                        ))}
                      </div>
                    ))}
                  </div>
                );
              });
            })()}
          </div>
        ) : showMap ? (
          <div className="flex-1 overflow-hidden relative">
            <Map
              initialViewState={{ longitude: 127.8, latitude: 35.5, zoom: 6.2 }}
              mapStyle={currentMapStyle}
              style={{ width: '100%', height: '100%' }}
              attributionControl={false}
            >
              <S57EncOverlay visible={mapToggles['s57'] ?? false} />
              {filtered
                .filter((c) => c.lon && c.lat)
                .map((cam) => (
                  <Marker
                    key={cam.cctvSn}
                    longitude={cam.lon!}
                    latitude={cam.lat!}
                    anchor="bottom"
                    onClick={(e) => {
                      e.originalEvent.stopPropagation();
                      setMapPopup(cam);
                    }}
                  >
                    <div
                      className="flex flex-col items-center cursor-pointer group"
                      title={cam.cameraNm}
                    >
                      {/* CCTV 아이콘 */}
                      <svg
                        width="24"
                        height="24"
                        viewBox="0 0 24 24"
                        fill="none"
                        className="drop-shadow-md transition-transform group-hover:scale-110"
                      >
                        {/* 카메라 본체 */}
                        <rect
                          x="4"
                          y="6"
                          width="12"
                          height="9"
                          rx="2"
                          fill={
                            cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)'
                          }
                          stroke="var(--static-white)"
                          strokeWidth="1.5"
                        />
                        {/* 렌즈 */}
                        <circle
                          cx="10"
                          cy="10.5"
                          r="2.5"
                          fill="var(--static-white)"
                          fillOpacity="0.8"
                        />
                        <circle
                          cx="10"
                          cy="10.5"
                          r="1.2"
                          fill={
                            cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)'
                          }
                        />
                        {/* 마운트 기둥 */}
                        <rect
                          x="17"
                          y="8"
                          width="3"
                          height="2"
                          rx="0.5"
                          fill={
                            cam.sttsCd === 'LIVE' ? 'var(--color-success)' : 'var(--fg-disabled)'
                          }
                          stroke="var(--static-white)"
                          strokeWidth="1"
                        />
                        <rect
                          x="19"
                          y="6"
                          width="1.5"
                          height="12"
                          fill="var(--static-white)"
                          fillOpacity="0.9"
                        />
                        {/* LIVE 표시등 */}
                        {cam.sttsCd === 'LIVE' && (
                          <circle cx="6.5" cy="8" r="1" fill="var(--color-danger)">
                            <animate
                              attributeName="opacity"
                              values="1;0.3;1"
                              dur="1.5s"
                              repeatCount="indefinite"
                            />
                          </circle>
                        )}
                      </svg>
                      {/* 이름 라벨 */}
                      <div
                        className="px-1 py-px rounded text-caption font-bold font-korean whitespace-nowrap mt-0.5"
                        style={{
                          background: 'rgba(0,0,0,.65)',
                          color: '#fff',
                          maxWidth: 80,
                          overflow: 'hidden',
                          textOverflow: 'ellipsis',
                        }}
                      >
                        {cam.cameraNm}
                      </div>
                    </div>
                  </Marker>
                ))}
              {mapPopup && mapPopup.lon && mapPopup.lat && (
                <Popup
                  longitude={mapPopup.lon}
                  latitude={mapPopup.lat}
                  anchor="bottom"
                  onClose={() => setMapPopup(null)}
                  closeOnClick={false}
                  offset={14}
                  className="cctv-dark-popup"
                >
                  <div
                    className="p-2"
                    style={{ minWidth: 150, background: 'var(--bg-card)', borderRadius: 6 }}
                  >
                    <div className="text-label-2 font-bold text-fg mb-1">{mapPopup.cameraNm}</div>
                    <div className="text-caption text-fg-disabled mb-1.5">
                      {mapPopup.locDc ?? ''}
                    </div>
                    <div className="flex items-center gap-1.5 mb-2">
                      <span
                        className="text-caption font-bold px-1.5 py-px rounded-full"
                        style={
                          mapPopup.sttsCd === 'LIVE'
                            ? {
                                background:
                                  'color-mix(in srgb, var(--color-success) 20%, transparent)',
                                color: 'var(--color-success)',
                              }
                            : {
                                background:
                                  'color-mix(in srgb, var(--fg-disabled) 15%, transparent)',
                                color: 'var(--fg-disabled)',
                              }
                        }
                      >
                        {mapPopup.sttsCd === 'LIVE' ? '● LIVE' : '● OFF'}
                      </span>
                      <span className="text-caption text-fg-disabled">{mapPopup.sourceNm}</span>
                    </div>
                    <button
                      onClick={() => {
                        handleSelectCamera(mapPopup);
                        setMapPopup(null);
                      }}
                      className="w-full px-2 py-1.5 rounded text-label-1 font-bold cursor-pointer border transition-colors hover:brightness-125"
                      style={{
                        background: 'rgba(6,182,212,.15)',
                        borderColor: 'rgba(6,182,212,.3)',
                        color: 'var(--color-accent)',
                      }}
                    >
                      ▶ 영상 보기
                    </button>
                  </div>
                </Popup>
              )}
            </Map>
            {/* 지도 위 안내 배지 */}
            <div
              className="absolute top-3 left-1/2 -translate-x-1/2 px-3 py-1.5 rounded-full text-label-1 font-bold font-korean z-10"
              style={{
                background: 'rgba(0,0,0,.7)',
                color: 'rgba(255,255,255,.7)',
                backdropFilter: 'blur(4px)',
              }}
            >
              📹 CCTV 마커를 클릭하여 영상을 선택하세요 ({filtered.length}개)
            </div>
          </div>
        ) : (
          <div
            className="flex-1 gap-0.5 p-0.5 overflow-hidden relative grid bg-black"
            style={{
              gridTemplateColumns: `repeat(${gridCols}, 1fr)`,
              gridTemplateRows: `repeat(${gridCols}, 1fr)`,
            }}
          >
            {Array.from({ length: totalCells }).map((_, i) => {
              const cam = activeCells[i];
              return (
                <div
                  key={i}
                  className="relative flex items-center justify-center overflow-hidden bg-bg-base"
                  style={{ border: '1px solid var(--stroke-light)' }}
                >
                  {cam ? (
                    <CCTVPlayer
                      ref={(el) => {
                        playerRefs.current[i] = el;
                      }}
                      cameraNm={cam.cameraNm}
                      streamUrl={cam.streamUrl}
                      sttsCd={cam.sttsCd}
                      coordDc={cam.coordDc}
                      sourceNm={cam.sourceNm}
                      cellIndex={i}
                      onClose={() => {
                        setActiveCells((prev) => prev.filter((c) => c.cctvSn !== cam.cctvSn));
                        if (gridMode === 1) setSelectedCamera(null);
                      }}
                      oilDetectionEnabled={oilDetectionEnabled && gridMode !== 9}
                      vesselDetectionEnabled={vesselDetectionEnabled && gridMode !== 9}
                      intrusionDetectionEnabled={intrusionDetectionEnabled && gridMode !== 9}
                    />
                  ) : (
                    <div className="text-label-1 text-fg-disabled font-korean opacity-40">
                      카메라를 선택하세요
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}

        {/* 하단 정보 바 */}
        <div className="flex items-center gap-3.5 px-4 py-1.5 border-t border-stroke bg-bg-elevated shrink-0">
          <div className="text-label-1 text-fg-disabled font-korean">
            선택: <b className="text-fg">{selectedCamera?.cameraNm ?? '–'}</b>
          </div>
          <div className="text-label-1 text-fg-disabled font-korean">
            위치: <span className="text-fg-sub">{selectedCamera?.locDc ?? '–'}</span>
          </div>
          <div className="text-label-1 text-fg-disabled font-korean">
            좌표:{' '}
            <span className="text-color-accent font-mono text-caption">
              {selectedCamera?.coordDc ?? '–'}
            </span>
          </div>
          <div className="ml-auto text-caption text-fg-disabled font-korean">
            API: 국립해양조사원 TAGO 해양 CCTV
          </div>
        </div>
      </div>

      {/* 오른쪽: 미니맵 + 정보 */}
      <div className="flex flex-col overflow-hidden bg-bg-surface border-l border-stroke w-[232px] min-w-[232px]">
        {/* 지도 헤더 */}
        <div className="px-3 py-2 border-b border-stroke text-label-2 font-bold text-fg font-korean bg-bg-elevated shrink-0 flex items-center justify-between">
          <span>🗺 위치 지도</span>
          <span className="text-caption text-fg-disabled font-normal">클릭하여 선택</span>
        </div>
        {/* 미니맵 */}
        <div className="w-full shrink-0 relative h-[210px] overflow-hidden">
          <Map
            initialViewState={{ longitude: 127.8, latitude: 35.5, zoom: 5.3 }}
            mapStyle={currentMapStyle}
            style={{ width: '100%', height: '100%' }}
            attributionControl={false}
            interactive={true}
          >
            <S57EncOverlay visible={mapToggles['s57'] ?? false} />
            {cameras
              .filter((c) => c.lon && c.lat)
              .map((cam) => (
                <Marker
                  key={`mini-${cam.cctvSn}`}
                  longitude={cam.lon!}
                  latitude={cam.lat!}
                  anchor="center"
                  onClick={(e) => {
                    e.originalEvent.stopPropagation();
                    handleSelectCamera(cam);
                  }}
                >
                  <div
                    className="cursor-pointer"
                    style={{
                      width: selectedCamera?.cctvSn === cam.cctvSn ? 10 : 7,
                      height: selectedCamera?.cctvSn === cam.cctvSn ? 10 : 7,
                      borderRadius: '50%',
                      background:
                        selectedCamera?.cctvSn === cam.cctvSn
                          ? 'var(--color-accent)'
                          : cam.sttsCd === 'LIVE'
                            ? 'var(--color-success)'
                            : 'var(--fg-disabled)',
                      boxShadow:
                        selectedCamera?.cctvSn === cam.cctvSn
                          ? '0 0 8px var(--color-accent)'
                          : 'none',
                      border: '1.5px solid rgba(255,255,255,.7)',
                    }}
                  />
                </Marker>
              ))}
          </Map>
        </div>

        {/* 카메라 정보 */}
        <div
          className="flex-1 overflow-y-auto px-3 py-2.5 border-t border-stroke"
          style={{ scrollbarWidth: 'thin', scrollbarColor: 'var(--stroke-light) transparent' }}
        >
          <div className="text-label-1 font-bold text-fg-sub font-korean mb-2">📋 카메라 정보</div>
          {selectedCamera ? (
            <div className="flex flex-col gap-1.5">
              {[
                ['카메라명', selectedCamera.cameraNm],
                ['지역', selectedCamera.regionNm],
                ['위치', selectedCamera.locDc ?? '—'],
                ['좌표', selectedCamera.coordDc ?? '—'],
                ['상태', selectedCamera.sttsCd === 'LIVE' ? '● 송출중' : '● 오프라인'],
                ['PTZ', selectedCamera.ptzYn === 'Y' ? '지원' : '미지원'],
                ['출처', selectedCamera.sourceNm ?? '—'],
              ].map(([k, v], i) => (
                <div
                  key={i}
                  className="flex justify-between px-2 py-1 bg-bg-base rounded text-caption"
                >
                  <span className="text-fg-disabled font-korean">{k}</span>
                  <span className="font-mono text-fg">{v}</span>
                </div>
              ))}
            </div>
          ) : (
            <div className="text-label-1 text-fg-disabled font-korean">카메라를 선택하세요</div>
          )}

          {/* 방제 즐겨찾기 */}
          <div className="mt-3 pt-2.5 border-t border-stroke">
            <div className="text-label-1 font-bold text-fg-sub font-korean mb-2">
              ⭐ 방제 핵심 지점
            </div>
            <div className="flex flex-col gap-1">
              {cctvFavorites.map((fav, i) => (
                <div
                  key={i}
                  className="flex items-center gap-2 px-2 py-1.5 bg-bg-card rounded-[5px] cursor-pointer hover:bg-bg-surface-hover transition-colors"
                  onClick={() => {
                    const found = cameras.find((c) => c.cameraNm === fav.name);
                    if (found) handleSelectCamera(found);
                  }}
                >
                  <span className="text-caption">⭐</span>
                  <div className="flex-1 min-w-0">
                    <div className="text-caption font-semibold text-fg font-korean truncate">
                      {fav.name}
                    </div>
                    <div className="text-caption text-fg-disabled font-korean">{fav.reason}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>

          {/* API 연동 현황 */}
          <div className="mt-3 pt-2.5 border-t border-stroke">
            <div className="text-label-1 font-bold text-fg-sub font-korean mb-2">
              🔌 API 연동 현황
            </div>
            <div className="flex flex-col gap-1.5">
              {[
                { name: '해양조사원 TAGO', status: '● 연결', color: 'var(--color-success)' },
                { name: 'KBS 재난안전포털', status: '● 연결', color: 'var(--color-success)' },
              ].map((api, i) => (
                <div
                  key={i}
                  className="flex items-center justify-between px-2 py-1 bg-bg-card rounded-[5px]"
                  style={{
                    border: '1px solid color-mix(in srgb, var(--color-success) 20%, transparent)',
                  }}
                >
                  <span className="text-caption text-fg-sub font-korean">{api.name}</span>
                  <span className="text-caption font-bold" style={{ color: api.color }}>
                    {api.status}
                  </span>
                </div>
              ))}
              <div
                className="flex items-center justify-between px-2 py-1 bg-bg-card rounded-[5px]"
                style={{
                  border: '1px solid color-mix(in srgb, var(--color-info) 20%, transparent)',
                }}
              >
                <span className="text-caption text-fg-sub font-korean">갱신 주기</span>
                <span className="text-caption font-bold font-mono text-color-info">1 fps</span>
              </div>
              <div className="text-caption text-fg-disabled font-mono text-right mt-0.5">
                최종갱신: {new Date().toLocaleTimeString('ko-KR')}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
