import { useState, useMemo, useRef, useEffect, forwardRef } from 'react';
import { MediaModal } from './MediaModal';

export interface Incident {
  id: string;
  name: string;
  status: 'active' | 'investigating' | 'closed';
  date: string;
  time: string;
  region: string;
  office: string;
  location: { lat: number; lon: number };
  causeType?: string;
  oilType?: string;
  prediction?: string;
  vesselName?: string;
  mediaCount?: number;
  hasImgAnalysis?: boolean;
}

interface IncidentsLeftPanelProps {
  incidents: Incident[];
  selectedIncidentId: string | null;
  onIncidentSelect: (id: string | null) => void;
  onFilteredChange?: (filtered: Incident[]) => void;
}

const PERIOD_PRESETS = ['오늘', '1주일', '1개월', '3개월', '6개월', '1년'] as const;
const REGIONS = ['전체', '남해청', '서해청', '동해청', '제주청', '중부청'] as const;

import { fetchIncidentWeather } from '../services/incidentsApi';
import type { WeatherInfo } from '../services/incidentsApi';

function formatDate(d: Date) {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${dd}`;
}

function getPresetStartDate(preset: string): string {
  const now = new Date();
  switch (preset) {
    case '오늘':
      return formatDate(now);
    case '1주일': {
      const d = new Date(now);
      d.setDate(d.getDate() - 7);
      return formatDate(d);
    }
    case '1개월': {
      const d = new Date(now);
      d.setMonth(d.getMonth() - 1);
      return formatDate(d);
    }
    case '3개월': {
      const d = new Date(now);
      d.setMonth(d.getMonth() - 3);
      return formatDate(d);
    }
    case '6개월': {
      const d = new Date(now);
      d.setMonth(d.getMonth() - 6);
      return formatDate(d);
    }
    case '1년': {
      const d = new Date(now);
      d.setFullYear(d.getFullYear() - 1);
      return formatDate(d);
    }
    default:
      return formatDate(now);
  }
}

export function IncidentsLeftPanel({
  incidents,
  selectedIncidentId,
  onIncidentSelect,
  onFilteredChange,
}: IncidentsLeftPanelProps) {
  const today = formatDate(new Date());
  const todayLabel = today.replace(/-/g, '-');

  const [searchTerm, setSearchTerm] = useState('');
  const [selectedPeriod, setSelectedPeriod] = useState<string>('1개월');
  const [dateFrom, setDateFrom] = useState(getPresetStartDate('1개월'));
  const [dateTo, setDateTo] = useState(today);
  const [selectedRegion, setSelectedRegion] = useState<string>('전체');
  const [selectedStatus, setSelectedStatus] = useState<string>('전체');

  // Media modal
  const [mediaModalIncident, setMediaModalIncident] = useState<Incident | null>(null);

  // Weather popup
  const [weatherPopupId, setWeatherPopupId] = useState<string | null>(null);
  const [weatherPos, setWeatherPos] = useState<{ top: number; left: number }>({ top: 0, left: 0 });
  // undefined = 로딩 중, null = 데이터 없음, WeatherInfo = 데이터 있음
  const [weatherInfo, setWeatherInfo] = useState<WeatherInfo | null | undefined>(undefined);
  const weatherRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!weatherPopupId) return;
    let cancelled = false;
    fetchIncidentWeather(parseInt(weatherPopupId)).then((data) => {
      if (!cancelled) setWeatherInfo(data);
    });
    return () => {
      cancelled = true;
      setWeatherInfo(undefined);
    };
  }, [weatherPopupId]);

  useEffect(() => {
    if (!weatherPopupId) return;
    const handler = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      if (
        weatherRef.current &&
        !weatherRef.current.contains(target) &&
        !target.closest('.inc-wx-btn')
      ) {
        setWeatherPopupId(null);
      }
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [weatherPopupId]);

  const handleWeatherClick = (e: React.MouseEvent, incId: string) => {
    e.stopPropagation();
    if (weatherPopupId === incId) {
      setWeatherPopupId(null);
      return;
    }
    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
    let top = rect.bottom + 6;
    let left = rect.left;
    if (top + 480 > window.innerHeight) top = rect.top - 480;
    if (left + 280 > window.innerWidth) left = window.innerWidth - 290;
    if (left < 10) left = 10;
    setWeatherPos({ top, left });
    setWeatherPopupId(incId);
  };

  const filteredIncidents = useMemo(() => {
    return incidents.filter((incident) => {
      const matchesSearch =
        incident.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
        (incident.vesselName &&
          incident.vesselName.toLowerCase().includes(searchTerm.toLowerCase()));
      const matchesRegion = selectedRegion === '전체' || incident.region === selectedRegion;
      const matchesStatus =
        selectedStatus === '전체' ||
        (selectedStatus === 'active' && incident.status === 'active') ||
        (selectedStatus === 'investigating' && incident.status === 'investigating') ||
        (selectedStatus === 'closed' && incident.status === 'closed');
      const matchesDate = incident.date >= dateFrom && incident.date <= dateTo;
      return matchesSearch && matchesRegion && matchesStatus && matchesDate;
    });
  }, [incidents, searchTerm, selectedRegion, selectedStatus, dateFrom, dateTo]);

  useEffect(() => {
    onFilteredChange?.(filteredIncidents);
  }, [filteredIncidents, onFilteredChange]);

  const regionCounts = useMemo(() => {
    const dateFiltered = incidents.filter((i) => {
      const matchesSearch =
        i.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
        (i.vesselName && i.vesselName.toLowerCase().includes(searchTerm.toLowerCase()));
      const matchesDate = i.date >= dateFrom && i.date <= dateTo;
      return matchesSearch && matchesDate;
    });
    const counts: Record<string, number> = { 전체: dateFiltered.length };
    REGIONS.forEach((r) => {
      if (r !== '전체') counts[r] = dateFiltered.filter((i) => i.region === r).length;
    });
    return counts;
  }, [incidents, searchTerm, dateFrom, dateTo]);

  const statusCounts = useMemo(() => {
    const base = incidents.filter((i) => {
      const matchesSearch =
        i.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
        (i.vesselName && i.vesselName.toLowerCase().includes(searchTerm.toLowerCase()));
      const matchesRegion = selectedRegion === '전체' || i.region === selectedRegion;
      const matchesDate = i.date >= dateFrom && i.date <= dateTo;
      return matchesSearch && matchesRegion && matchesDate;
    });
    return {
      active: base.filter((i) => i.status === 'active').length,
      investigating: base.filter((i) => i.status === 'investigating').length,
      closed: base.filter((i) => i.status === 'closed').length,
    };
  }, [incidents, searchTerm, selectedRegion, dateFrom, dateTo]);

  // Pagination
  const pageSize = 6;
  const [currentPage, setCurrentPage] = useState(1);
  const totalPages = Math.max(1, Math.ceil(filteredIncidents.length / pageSize));
  const safePage = Math.min(currentPage, totalPages);
  const pagedIncidents = filteredIncidents.slice((safePage - 1) * pageSize, safePage * pageSize);
  const resetPage = () => setCurrentPage(1);

  const handlePeriodClick = (preset: string) => {
    setSelectedPeriod(preset);
    setDateFrom(getPresetStartDate(preset));
    setDateTo(today);
    resetPage();
  };

  return (
    <div className="flex flex-col bg-bg-surface border-r border-stroke overflow-hidden shrink-0 w-[360px]">
      {/* Search */}
      <div className="px-4 py-3 border-b border-stroke shrink-0">
        <div className="relative">
          <span className="absolute left-[10px] top-1/2 -translate-y-1/2 text-caption">🔍</span>
          <input
            type="text"
            placeholder="사고명, 선박명 검색..."
            value={searchTerm}
            onChange={(e) => {
              setSearchTerm(e.target.value);
              resetPage();
            }}
            className="w-full py-2 pr-3 pl-8 bg-bg-base border border-stroke text-caption outline-none"
            style={{ borderRadius: 'var(--radius-sm)' }}
          />
        </div>
      </div>

      {/* Date Range */}
      <div className="flex items-center gap-1.5 px-4 py-2 border-b border-stroke shrink-0">
        <input
          type="date"
          value={dateFrom}
          onChange={(e) => {
            setDateFrom(e.target.value);
            setSelectedPeriod('');
            resetPage();
          }}
          className="bg-bg-base border border-stroke font-mono text-label-2 outline-none flex-1"
          style={{ padding: '5px 8px', borderRadius: 'var(--radius-sm)' }}
        />
        <span className="text-fg-disabled text-label-2">~</span>
        <input
          type="date"
          value={dateTo}
          onChange={(e) => {
            setDateTo(e.target.value);
            setSelectedPeriod('');
            resetPage();
          }}
          className="bg-bg-base border border-stroke font-mono text-label-2 outline-none flex-1"
          style={{ padding: '5px 8px', borderRadius: 'var(--radius-sm)' }}
        />
        <button
          onClick={resetPage}
          className="rounded-sm text-label-2 font-semibold cursor-pointer whitespace-nowrap text-color-accent"
          style={{
            padding: '5px 12px',
            border: '1px solid rgba(6,182,212,.3)',
            background: 'rgba(6,182,212,.08)',
          }}
        >
          조회
        </button>
      </div>

      {/* Period Presets */}
      <div className="flex gap-1 px-4 py-1.5 border-b border-stroke shrink-0">
        {PERIOD_PRESETS.map((p) => (
          <button
            key={p}
            onClick={() => handlePeriodClick(p)}
            className="text-caption font-semibold cursor-pointer"
            style={{
              padding: '3px 8px',
              borderRadius: '14px',
              border:
                selectedPeriod === p
                  ? '1px solid rgba(6,182,212,0.3)'
                  : '1px solid var(--stroke-default)',
              background: selectedPeriod === p ? 'rgba(6,182,212,0.1)' : 'transparent',
              color: selectedPeriod === p ? 'var(--color-accent)' : 'var(--fg-disabled)',
            }}
          >
            {p}
          </button>
        ))}
      </div>

      {/* Today Summary */}
      <div
        className="px-4 py-2.5 border-b border-stroke shrink-0"
        style={{ background: 'rgba(6,182,212,0.03)' }}
      >
        <div
          className="text-caption font-bold text-fg-disabled mb-2"
          style={{ letterSpacing: '0.8px' }}
        >
          📅 오늘 ({todayLabel}) 사고 현황
        </div>
        <div className="flex gap-1.5 flex-wrap">
          {REGIONS.map((r) => {
            const count = regionCounts[r] ?? 0;
            const isActive = selectedRegion === r;
            return (
              <button
                key={r}
                onClick={() => {
                  setSelectedRegion(r);
                  resetPage();
                }}
                className="text-label-2 cursor-pointer"
                style={{
                  padding: '4px 10px',
                  borderRadius: 'var(--radius-sm)',
                  background: isActive ? 'rgba(6,182,212,0.1)' : 'var(--bg-card)',
                  border: isActive
                    ? '1px solid rgba(6,182,212,0.25)'
                    : '1px solid var(--stroke-default)',
                  color: isActive ? 'var(--color-accent)' : 'var(--fg-sub)',
                  fontWeight: isActive ? 700 : 400,
                }}
              >
                {r === '전체' ? '전체 ' : `${r} `}
                <span
                  className="font-bold font-mono"
                  style={{ color: isActive ? 'var(--color-accent)' : undefined }}
                >
                  {r === '전체' ? count : `(${count})`}
                </span>
              </button>
            );
          })}
        </div>
      </div>

      {/* Status Filter */}
      <div className="flex gap-[5px] px-4 py-2 border-b border-stroke shrink-0">
        {[
          { id: '전체', label: '전체', dot: '' },
          { id: 'active', label: `대응중 (${statusCounts.active})`, dot: 'var(--color-danger)' },
          {
            id: 'investigating',
            label: `조사중 (${statusCounts.investigating})`,
            dot: 'var(--color-warning)',
          },
          { id: 'closed', label: `종료 (${statusCounts.closed})`, dot: 'var(--fg-disabled)' },
        ].map((s) => (
          <button
            key={s.id}
            onClick={() => {
              setSelectedStatus(s.id);
              resetPage();
            }}
            className="flex items-center gap-1 text-caption cursor-pointer"
            style={{
              padding: '4px 10px',
              borderRadius: '12px',
              border:
                selectedStatus === s.id
                  ? '1px solid rgba(6,182,212,0.3)'
                  : '1px solid var(--stroke-default)',
              background: 'transparent',
              color: selectedStatus === s.id ? 'var(--fg-sub)' : 'var(--fg-disabled)',
            }}
          >
            {s.dot && (
              <span
                style={{ width: '6px', height: '6px', borderRadius: '50%', background: s.dot }}
              />
            )}
            {s.label}
          </button>
        ))}
      </div>

      {/* Count */}
      <div className="px-4 py-1.5 text-label-2 text-fg-disabled shrink-0 border-b border-stroke">
        총 {filteredIncidents.length}건
      </div>

      {/* Incident List */}
      <div
        className="flex-1 overflow-y-auto"
        style={{
          scrollbarWidth: 'thin' as const,
          scrollbarColor: 'var(--stroke-light) transparent',
        }}
      >
        {pagedIncidents.length === 0 ? (
          <div className="px-4 py-10 text-center text-fg-disabled text-label-2">
            검색 결과가 없습니다.
          </div>
        ) : (
          pagedIncidents.map((inc) => {
            const isSel = selectedIncidentId === inc.id;
            const dotStyle: Record<string, string> = {
              active: 'var(--color-danger)',
              investigating: 'var(--color-warning)',
              closed: 'var(--fg-disabled)',
            };
            const dotShadow: Record<string, string> = {
              active: '0 0 6px var(--color-danger)',
              investigating: '0 0 6px var(--color-warning)',
              closed: 'none',
            };
            const stBg: Record<string, string> = {
              active: 'rgba(239,68,68,0.15)',
              investigating: 'rgba(249,115,22,0.15)',
              closed: 'rgba(100,116,139,0.15)',
            };
            const stColor: Record<string, string> = {
              active: 'var(--color-danger)',
              investigating: 'var(--color-warning)',
              closed: 'var(--fg-disabled)',
            };
            const stLabel: Record<string, string> = {
              active: '대응중',
              investigating: '조사중',
              closed: '종료',
            };
            return (
              <div
                key={inc.id}
                onClick={() => onIncidentSelect(isSel ? null : inc.id)}
                className="px-4 py-3 border-b border-stroke cursor-pointer"
                style={{
                  background: isSel ? 'rgba(6,182,212,0.04)' : undefined,
                  borderLeft: isSel ? '3px solid var(--color-accent)' : '3px solid transparent',
                  transition: 'background 0.15s',
                }}
                onMouseEnter={(e) => {
                  if (!isSel) e.currentTarget.style.background = 'rgba(255,255,255,0.02)';
                }}
                onMouseLeave={(e) => {
                  if (!isSel) e.currentTarget.style.background = '';
                }}
              >
                {/* Row 1: name + status */}
                <div className="flex items-center justify-between mb-[5px]">
                  <div className="flex items-center gap-1.5 text-caption">
                    <span
                      className="shrink-0"
                      style={{
                        width: '8px',
                        height: '8px',
                        borderRadius: '50%',
                        background: dotStyle[inc.status],
                        boxShadow: dotShadow[inc.status],
                      }}
                    />
                    {inc.name}
                  </div>
                  <span
                    className="shrink-0 text-caption"
                    style={{
                      padding: '2px 10px',
                      borderRadius: '10px',
                      background: stBg[inc.status],
                      color: stColor[inc.status],
                    }}
                  >
                    {stLabel[inc.status]}
                  </span>
                </div>
                {/* Row 2: meta */}
                <div className="flex items-center gap-2 text-caption text-fg-disabled mb-[5px]">
                  <span>
                    {inc.date} {inc.time}
                  </span>
                  <span> {inc.office}</span>
                </div>
                {/* Row 3: tags + buttons */}
                <div className="flex items-center justify-between">
                  <div className="flex flex-wrap gap-1">
                    {inc.causeType && (
                      <span
                        className="text-caption font-medium text-fg-sub"
                        style={{
                          padding: '2px 8px',
                          borderRadius: '3px',
                          background: 'rgba(100,116,139,0.08)',
                          border: '1px solid rgba(100,116,139,0.2)',
                        }}
                      >
                        {inc.causeType}
                      </span>
                    )}
                    {inc.oilType && (
                      <span
                        className="text-caption font-medium text-fg-sub"
                        style={{
                          padding: '2px 8px',
                          borderRadius: '3px',
                          background: 'rgba(100,116,139,0.08)',
                          border: '1px solid rgba(100,116,139,0.2)',
                        }}
                      >
                        {inc.oilType}
                      </span>
                    )}
                    {inc.prediction && (
                      <span
                        className="text-caption font-medium text-fg-sub"
                        style={{
                          padding: '2px 8px',
                          borderRadius: '3px',
                          background: 'rgba(100,116,139,0.08)',
                          border: '1px solid rgba(100,116,139,0.2)',
                        }}
                      >
                        {inc.prediction}
                      </span>
                    )}
                  </div>
                  <div className="flex gap-1">
                    <button
                      className="inc-wx-btn cursor-pointer text-label-2"
                      onClick={(e) => handleWeatherClick(e, inc.id)}
                      title="사고 위치 기상정보"
                      style={{
                        padding: '3px 7px',
                        borderRadius: '4px',
                        lineHeight: 1,
                        border: '1px solid rgba(59,130,246,0.25)',
                        background:
                          weatherPopupId === inc.id
                            ? 'rgba(59,130,246,0.18)'
                            : 'rgba(59,130,246,0.08)',
                        color: '#60a5fa',
                        transition: '0.15s',
                      }}
                    >
                      기상정보
                    </button>
                    {(inc.mediaCount ?? 0) > 0 && (
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          setMediaModalIncident(inc);
                        }}
                        title="현장정보 조회"
                        className="cursor-pointer text-label-2"
                        style={{
                          padding: '3px 7px',
                          borderRadius: '4px',
                          lineHeight: 1,
                          border: '1px solid rgba(59,130,246,0.25)',
                          background: 'rgba(59,130,246,0.08)',
                          color: '#60a5fa',
                          transition: '0.15s',
                        }}
                      >
                        <span className="text-caption">{inc.mediaCount}</span>
                      </button>
                    )}
                    {inc.hasImgAnalysis && (
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          setMediaModalIncident(inc);
                        }}
                        title="현장 이미지 보기"
                        className="cursor-pointer text-label-2"
                        style={{
                          padding: '3px 7px',
                          borderRadius: '4px',
                          lineHeight: 1,
                          border: '1px solid rgba(59,130,246,0.25)',
                          background: 'rgba(59,130,246,0.08)',
                          color: '#60a5fa',
                          transition: '0.15s',
                        }}
                      >
                        📷
                      </button>
                    )}
                  </div>
                </div>
              </div>
            );
          })
        )}
      </div>

      {/* Media Modal */}
      {mediaModalIncident && (
        <MediaModal incident={mediaModalIncident} onClose={() => setMediaModalIncident(null)} />
      )}

      {/* Weather Popup (fixed position) */}
      {weatherPopupId && weatherInfo !== undefined && (
        <WeatherPopup
          ref={weatherRef}
          data={weatherInfo}
          position={weatherPos}
          onClose={() => setWeatherPopupId(null)}
        />
      )}

      {/* Pagination */}
      <div className="flex items-center justify-between bg-bg-surface shrink-0 border-t border-stroke px-3 py-2">
        <div className="text-caption text-fg-disabled">
          총 <b>{filteredIncidents.length}</b>건 중 {(safePage - 1) * pageSize + 1}-
          {Math.min(safePage * pageSize, filteredIncidents.length)}
        </div>
        <div className="flex items-center gap-[3px]">
          <PgBtn label="⏮" disabled={safePage <= 1} onClick={() => setCurrentPage(1)} />
          <PgBtn
            label="◀"
            disabled={safePage <= 1}
            onClick={() => setCurrentPage(Math.max(1, safePage - 1))}
          />
          {Array.from({ length: totalPages }, (_, i) => i + 1)
            .filter((p) => Math.abs(p - safePage) <= 2)
            .map((p) => (
              <PgBtn
                key={p}
                label={String(p)}
                active={p === safePage}
                onClick={() => setCurrentPage(p)}
              />
            ))}
          <PgBtn
            label="▶"
            disabled={safePage >= totalPages}
            onClick={() => setCurrentPage(Math.min(totalPages, safePage + 1))}
          />
          <PgBtn
            label="⏭"
            disabled={safePage >= totalPages}
            onClick={() => setCurrentPage(totalPages)}
          />
        </div>
        <select
          onChange={(e) => {
            /* page size change placeholder */ void e;
          }}
          className="bg-bg-base border border-stroke text-fg-sub text-caption outline-none rounded px-1.5 py-[3px]"
        >
          <option>6건</option>
          <option>10건</option>
          <option>20건</option>
        </select>
      </div>
    </div>
  );
}

function PgBtn({
  label,
  active,
  disabled,
  onClick,
}: {
  label: string;
  active?: boolean;
  disabled?: boolean;
  onClick: () => void;
}) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className="flex items-center justify-center font-mono text-caption"
      style={{
        minWidth: '24px',
        height: '24px',
        padding: '0 5px',
        borderRadius: '4px',
        fontWeight: active ? 700 : 600,
        background: active ? 'rgba(6,182,212,0.15)' : 'var(--bg-card)',
        border: active ? '1px solid rgba(6,182,212,0.4)' : '1px solid var(--stroke-default)',
        color: active ? 'var(--color-accent)' : 'var(--fg-disabled)',
        opacity: disabled ? 0.4 : 1,
        pointerEvents: disabled ? 'none' : undefined,
        cursor: disabled ? 'default' : 'pointer',
      }}
    >
      {label}
    </button>
  );
}

/* ════════════════════════════════════════════════════
   WeatherPopup – 사고 위치 기상정보 팝업
   ════════════════════════════════════════════════════ */
const WeatherPopup = forwardRef<
  HTMLDivElement,
  {
    data: WeatherInfo | null;
    position: { top: number; left: number };
    onClose: () => void;
  }
>(({ data, position, onClose }, ref) => {
  const forecast = data?.forecast ?? [];
  return (
    <div
      ref={ref}
      className="fixed overflow-hidden rounded-xl border border-stroke bg-bg-surface"
      style={{
        zIndex: 9990,
        width: 280,
        top: position.top,
        left: position.left,
        borderColor: 'rgba(59,130,246,0.3)',
        boxShadow: '0 12px 40px rgba(0,0,0,0.5)',
        backdropFilter: 'blur(12px)',
      }}
    >
      {/* Header */}
      <div
        className="flex items-center justify-between border-b border-stroke px-3.5 py-2.5"
        style={{
          background: 'linear-gradient(135deg, rgba(59,130,246,0.08), rgba(6,182,212,0.04))',
        }}
      >
        <div className="flex items-center gap-1.5">
          <span className="text-body-2">🌤</span>
          <div>
            <div className="text-label-2 font-bold">{data?.locNm || '기상정보 없음'}</div>
            <div className="text-fg-disabled font-mono text-caption">{data?.obsDtm || '-'}</div>
          </div>
        </div>
        <span onClick={onClose} className="cursor-pointer text-fg-disabled text-body-2 p-0.5">
          ✕
        </span>
      </div>

      {/* Body */}
      <div className="px-3.5 py-3">
        {/* Main weather */}
        <div className="flex items-center gap-3 mb-2.5">
          <div className="text-[28px]">{data?.icon || '❓'}</div>
          <div>
            <div className="font-bold font-mono text-[20px]">{data?.temp || '-'}</div>
            <div className="text-fg-disabled text-caption">{data?.weatherDc || '-'}</div>
          </div>
        </div>

        {/* Detail grid */}
        <div className="grid grid-cols-2 gap-1.5 text-caption">
          <WxCell icon="💨" label="풍향/풍속" value={data?.wind} />
          <WxCell icon="🌊" label="파고" value={data?.wave} />
          <WxCell icon="💧" label="습도" value={data?.humid} />
          <WxCell icon="👁" label="시정" value={data?.vis} />
          <WxCell icon="🌡" label="수온" value={data?.sst} />
          <WxCell icon="🔄" label="조류" value={data?.tide} />
        </div>

        {/* Tide info */}
        <div className="flex gap-1.5 mt-2">
          <div
            className="flex-1 flex items-center gap-1.5 px-2 py-1.5 rounded-md"
            style={{
              background: 'rgba(59,130,246,0.06)',
              border: '1px solid rgba(59,130,246,0.1)',
            }}
          >
            <span className="text-caption">⬆</span>
            <div>
              <div className="text-fg-disabled text-caption">고조 (만조)</div>
              <div className="font-bold font-mono text-caption text-color-info">
                {data?.highTide || '-'}
              </div>
            </div>
          </div>
          <div
            className="flex-1 flex items-center gap-1.5 px-2 py-1.5 rounded-md"
            style={{ background: 'rgba(6,182,212,0.06)', border: '1px solid rgba(6,182,212,0.1)' }}
          >
            <span className="text-caption">⬇</span>
            <div>
              <div className="text-fg-disabled text-caption">저조 (간조)</div>
              <div className="text-color-accent font-bold font-mono text-caption">
                {data?.lowTide || '-'}
              </div>
            </div>
          </div>
        </div>

        {/* 24h Forecast */}
        <div className="bg-bg-base mt-2.5 px-2.5 py-2 rounded-md">
          <div className="font-bold text-fg-disabled text-caption mb-1.5">24h 예보</div>
          {forecast.length > 0 ? (
            <div className="flex justify-between font-mono text-fg-sub text-caption">
              {forecast.map((f, i) => (
                <div key={i} className="text-center">
                  <div>{f.hour}</div>
                  <div className="text-caption my-0.5">{f.icon}</div>
                  <div className="font-semibold">{f.temp}</div>
                </div>
              ))}
            </div>
          ) : (
            <div className="text-fg-disabled text-center text-caption py-1">예보 데이터 없음</div>
          )}
        </div>

        {/* Impact */}
        <div
          className="mt-2 rounded"
          style={{
            padding: '6px 10px',
            background: 'rgba(249,115,22,0.05)',
            border: '1px solid rgba(249,115,22,0.12)',
          }}
        >
          <div className="font-bold text-color-warning text-caption mb-[3px]">⚠ 방제 작업 영향</div>
          <div className="text-fg-sub text-caption leading-[1.5]">{data?.impactDc || '-'}</div>
        </div>
      </div>
    </div>
  );
});
WeatherPopup.displayName = 'WeatherPopup';

function WxCell({ icon, label, value }: { icon: string; label: string; value?: string | null }) {
  return (
    <div className="flex items-center bg-bg-base rounded gap-[6px] py-1.5 px-2">
      <span className="text-label-1">{icon}</span>
      <div>
        <div className="text-fg-disabled text-caption">{label}</div>
        <div className="font-semibold font-mono">{value || '-'}</div>
      </div>
    </div>
  );
}
