import { memo, useMemo, useState, useEffect, useRef, useCallback } from 'react';
import { Marker, Popup, Source, Layer, useMap } from 'react-map-gl/maplibre';
import { useTranslation } from 'react-i18next';
import type { Ship, ShipCategory } from '../../types';
import maplibregl from 'maplibre-gl';
import { detectFleet } from '../../utils/fleetDetection';
import type { FleetConnection } from '../../utils/fleetDetection';

interface Props {
  ships: Ship[];
  militaryOnly: boolean;
  koreanOnly?: boolean;
  hoveredMmsi?: string | null;
  focusMmsi?: string | null;
  onFocusClear?: () => void;
}

// ── MarineTraffic-style vessel type colors (CSS variable references) ──
const MT_TYPE_COLORS: Record<string, string> = {
  cargo:       'var(--kcg-ship-cargo)',
  tanker:      'var(--kcg-ship-tanker)',
  passenger:   'var(--kcg-ship-passenger)',
  fishing:     'var(--kcg-ship-fishing)',
  fishing_gear: '#f97316',
  pleasure:    'var(--kcg-ship-pleasure)',
  military:    'var(--kcg-ship-military)',
  tug_special: 'var(--kcg-ship-tug)',
  other:       'var(--kcg-ship-other)',
  unknown:     'var(--kcg-ship-unknown)',
};

// Resolved hex colors for MapLibre paint (which cannot use CSS vars)
const MT_TYPE_HEX: Record<string, string> = {
  cargo:       '#f0a830',
  tanker:      '#e74c3c',
  passenger:   '#4caf50',
  fishing:     '#42a5f5',
  fishing_gear: '#f97316',
  pleasure:    '#e91e8c',
  military:    '#d32f2f',
  tug_special: '#2e7d32',
  other:       '#5c6bc0',
  unknown:     '#9e9e9e',
};

// Map our internal ShipCategory + typecode → MT visual type
function getMTType(ship: Ship): string {
  const tc = (ship.typecode || '').toUpperCase();
  const cat = ship.category;

  // Military first
  if (cat === 'carrier' || cat === 'destroyer' || cat === 'warship' || cat === 'submarine' || cat === 'patrol') return 'military';
  if (tc === 'DDG' || tc === 'DDH' || tc === 'CVN' || tc === 'FFG' || tc === 'LCS' || tc === 'MCM' || tc === 'PC' || tc === 'LPH') return 'military';

  // Tanker
  if (cat === 'tanker') return 'tanker';
  if (tc === 'VLCC' || tc === 'LNG' || tc === 'LPG') return 'tanker';
  if (tc.startsWith('A1')) return 'tanker';

  // Cargo
  if (cat === 'cargo') return 'cargo';
  if (tc === 'CONT' || tc === 'BULK') return 'cargo';
  if (tc.startsWith('A2') || tc.startsWith('A3')) return 'cargo';

  // Passenger
  if (tc === 'PASS' || tc.startsWith('B')) return 'passenger';

  // Fishing
  if (tc.startsWith('C')) return 'fishing';

  // Tug / Special
  if (tc.startsWith('D') || tc.startsWith('E')) return 'tug_special';

  // Pleasure
  if (tc === 'SAIL' || tc === 'YACHT') return 'pleasure';

  if (cat === 'civilian') return 'other';
  return 'unknown';
}

// Legacy navy flag colors (for popup header accent only)
const NAVY_COLORS: Record<string, string> = {
  US: '#1e90ff', UK: '#e63946', FR: '#ffd60a', KR: '#00e5ff',
  IR: '#2ecc40', JP: '#ff6b6b', AU: '#f4a261', DE: '#b5b5b5', IN: '#ff9f43',
};

const FLAG_EMOJI: Record<string, string> = {
  US: '\u{1F1FA}\u{1F1F8}', UK: '\u{1F1EC}\u{1F1E7}', FR: '\u{1F1EB}\u{1F1F7}',
  KR: '\u{1F1F0}\u{1F1F7}', IR: '\u{1F1EE}\u{1F1F7}', JP: '\u{1F1EF}\u{1F1F5}',
  AU: '\u{1F1E6}\u{1F1FA}', DE: '\u{1F1E9}\u{1F1EA}', IN: '\u{1F1EE}\u{1F1F3}',
  CN: '\u{1F1E8}\u{1F1F3}', PA: '\u{1F1F5}\u{1F1E6}', LR: '\u{1F1F1}\u{1F1F7}',
  MH: '\u{1F1F2}\u{1F1ED}', HK: '\u{1F1ED}\u{1F1F0}', SG: '\u{1F1F8}\u{1F1EC}',
  BZ: '\u{1F1E7}\u{1F1FF}', OM: '\u{1F1F4}\u{1F1F2}', AE: '\u{1F1E6}\u{1F1EA}',
  SA: '\u{1F1F8}\u{1F1E6}', BH: '\u{1F1E7}\u{1F1ED}', QA: '\u{1F1F6}\u{1F1E6}',
};

// icon-size multiplier (symbol layer, base=64px)
const SIZE_MAP: Record<ShipCategory, number> = {
  carrier: 0.32, destroyer: 0.22, warship: 0.22, submarine: 0.18, patrol: 0.16,
  tanker: 0.16, cargo: 0.16, fishing: 0.14, civilian: 0.14, unknown: 0.12,
};

const MIL_CATEGORIES: ShipCategory[] = ['carrier', 'destroyer', 'warship', 'submarine', 'patrol'];

function isMilitary(category: ShipCategory): boolean {
  return MIL_CATEGORIES.includes(category);
}

function getShipColor(ship: Ship): string {
  return MT_TYPE_COLORS[getMTType(ship)] || MT_TYPE_COLORS.unknown;
}

function getShipHex(ship: Ship): string {
  return MT_TYPE_HEX[getMTType(ship)] || MT_TYPE_HEX.unknown;
}

// ── Local Korean ship photos ──
const LOCAL_SHIP_PHOTOS: Record<string, string> = {
  '440034000': '/ships/440034000.jpg',
  '440150000': '/ships/440150000.jpg',
  '440272000': '/ships/440272000.jpg',
  '440274000': '/ships/440274000.jpg',
  '440323000': '/ships/440323000.jpg',
  '440384000': '/ships/440384000.jpg',
  '440880000': '/ships/440880000.jpg',
  '441046000': '/ships/441046000.jpg',
  '441345000': '/ships/441345000.jpg',
  '441353000': '/ships/441353000.jpg',
  '441393000': '/ships/441393000.jpg',
  '441423000': '/ships/441423000.jpg',
  '441548000': '/ships/441548000.jpg',
  '441708000': '/ships/441708000.png',
  '441866000': '/ships/441866000.jpg',
};

interface VesselPhotoData { url: string; }
const vesselPhotoCache = new Map<string, VesselPhotoData | null>();

type PhotoSource = 'spglobal' | 'marinetraffic';

interface VesselPhotoProps {
  mmsi: string;
  imo?: string;
  shipImagePath?: string | null;
  shipImageCount?: number;
}

/**
 * S&P Global 이미지 목록 API 응답
 * GET /signal-batch/api/v1/shipimg/{imo}
 * path에 _1.jpg(썸네일) / _2.jpg(원본) 을 붙여서 사용
 */
interface SpgImageInfo {
  picId: number;
  path: string;       // e.g. "/shipimg/22738/2273823"
  copyright: string;
  date: string;
}

// IMO별 이미지 목록 캐시
const spgImageCache = new Map<string, SpgImageInfo[] | null>();

async function fetchSpgImages(imo: string): Promise<SpgImageInfo[]> {
  if (spgImageCache.has(imo)) return spgImageCache.get(imo) || [];
  try {
    const res = await fetch(`/signal-batch/api/v1/shipimg/${imo}`);
    if (!res.ok) throw new Error(`${res.status}`);
    const data: SpgImageInfo[] = await res.json();
    spgImageCache.set(imo, data);
    return data;
  } catch {
    spgImageCache.set(imo, null);
    return [];
  }
}

function VesselPhoto({ mmsi, imo, shipImagePath }: VesselPhotoProps) {
  const localUrl = LOCAL_SHIP_PHOTOS[mmsi];

  const hasSPGlobal = !!shipImagePath;
  const [activeTab, setActiveTab] = useState<PhotoSource>(hasSPGlobal ? 'spglobal' : 'marinetraffic');
  const [spgSlideIdx, setSpgSlideIdx] = useState(0);
  const [spgErrors, setSpgErrors] = useState<Set<number>>(new Set());
  const [spgImages, setSpgImages] = useState<SpgImageInfo[]>([]);

  // 모달이 다른 선박으로 변경될 때 리셋 + 이미지 목록 조회
  useEffect(() => {
    setActiveTab(hasSPGlobal ? 'spglobal' : 'marinetraffic');
    setSpgSlideIdx(0);
    setSpgErrors(new Set());
    setSpgImages([]);

    if (imo && hasSPGlobal) {
      fetchSpgImages(imo).then(setSpgImages);
    } else if (shipImagePath) {
      // IMO 없으면 shipImagePath 단일 이미지 사용
      setSpgImages([{ picId: 0, path: shipImagePath.replace(/_[12]\.\w+$/, ''), copyright: '', date: '' }]);
    }
  }, [mmsi, imo, hasSPGlobal, shipImagePath]);

  // S&P Global slide URLs: 각 이미지의 path + _2.jpg (원본)
  const spgUrls = useMemo(
    () => spgImages.map(img => `${img.path}_2.jpg`),
    [spgImages],
  );
  const validSpgCount = spgUrls.length;

  // MarineTraffic image state (lazy loaded)
  const [mtPhoto, setMtPhoto] = useState<VesselPhotoData | null | undefined>(() => {
    return vesselPhotoCache.has(mmsi) ? vesselPhotoCache.get(mmsi) : undefined;
  });

  useEffect(() => {
    setMtPhoto(vesselPhotoCache.has(mmsi) ? vesselPhotoCache.get(mmsi) : undefined);
  }, [mmsi]);

  useEffect(() => {
    if (activeTab !== 'marinetraffic') return;
    if (mtPhoto !== undefined) return;
    const imgUrl = `https://photos.marinetraffic.com/ais/showphoto.aspx?mmsi=${mmsi}&size=thumb300`;
    const img = new Image();
    img.onload = () => { const result = { url: imgUrl }; vesselPhotoCache.set(mmsi, result); setMtPhoto(result); };
    img.onerror = () => { vesselPhotoCache.set(mmsi, null); setMtPhoto(null); };
    img.src = imgUrl;
  }, [mmsi, activeTab, mtPhoto]);

  // Resolve current image URL
  let currentUrl: string | null = null;
  if (localUrl) {
    currentUrl = localUrl;
  } else if (activeTab === 'spglobal' && spgUrls.length > 0 && !spgErrors.has(spgSlideIdx)) {
    currentUrl = spgUrls[spgSlideIdx];
  } else if (activeTab === 'marinetraffic' && mtPhoto) {
    currentUrl = mtPhoto.url;
  }

  // If local photo exists, show it directly without tabs
  if (localUrl) {
    return (
      <div className="mb-1.5">
        <div className="vessel-photo-frame w-full rounded overflow-hidden bg-black/30">
          <img src={localUrl} alt="Vessel"
            className="w-full h-full object-contain"
            onError={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }}
          />
        </div>
      </div>
    );
  }

  const allSpgFailed = spgUrls.length > 0 && spgUrls.every((_, i) => spgErrors.has(i));
  const noPhoto = (!hasSPGlobal || allSpgFailed) && mtPhoto === null;

  return (
    <div className="mb-1.5">
      <div className="flex mb-1">
        {hasSPGlobal && (
          <div
            className={`flex-1 py-1.5 text-center cursor-pointer transition-all text-[12px] font-bold tracking-wide border-b-2 ${
              activeTab === 'spglobal'
                ? 'border-[#1565c0] text-white bg-white/5'
                : 'border-transparent text-kcg-muted hover:text-kcg-dim hover:bg-white/[0.03]'
            }`}
            onClick={() => setActiveTab('spglobal')}
          >
            S&P Global
          </div>
        )}
        <div
          className={`flex-1 py-1.5 text-center cursor-pointer transition-all text-[12px] font-bold tracking-wide border-b-2 ${
            activeTab === 'marinetraffic'
              ? 'border-[#1565c0] text-white bg-white/5'
              : 'border-transparent text-kcg-muted hover:text-kcg-dim hover:bg-white/[0.03]'
          }`}
          onClick={() => setActiveTab('marinetraffic')}
        >
          MarineTraffic
        </div>
      </div>

      {/* 고정 높이 사진 영역 */}
      <div className="vessel-photo-frame w-full rounded overflow-hidden bg-black/30 relative">
        {currentUrl ? (
          <img
            key={currentUrl}
            src={currentUrl}
            alt="Vessel"
            className="w-full h-full object-contain"
            onError={() => {
              if (activeTab === 'spglobal') {
                setSpgErrors(prev => new Set(prev).add(spgSlideIdx));
              }
            }}
          />
        ) : noPhoto ? (
          <div className="flex items-center justify-center h-full text-kcg-dim text-[10px]">
            No photo available
          </div>
        ) : activeTab === 'marinetraffic' && mtPhoto === undefined ? (
          <div className="flex items-center justify-center h-full text-kcg-dim text-[10px]">
            Loading...
          </div>
        ) : (
          <div className="flex items-center justify-center h-full text-kcg-dim text-[10px]">
            No photo available
          </div>
        )}

        {/* S&P Global 슬라이드 네비게이션 */}
        {activeTab === 'spglobal' && validSpgCount > 1 && (
          <>
            <button
              type="button"
              className="absolute left-1 top-1/2 -translate-y-1/2 bg-black/50 text-white rounded-full w-6 h-6 flex items-center justify-center text-xs hover:bg-black/70 transition-colors"
              onClick={(e) => { e.stopPropagation(); setSpgSlideIdx(i => (i - 1 + validSpgCount) % validSpgCount); }}
            >
              &lt;
            </button>
            <button
              type="button"
              className="absolute right-1 top-1/2 -translate-y-1/2 bg-black/50 text-white rounded-full w-6 h-6 flex items-center justify-center text-xs hover:bg-black/70 transition-colors"
              onClick={(e) => { e.stopPropagation(); setSpgSlideIdx(i => (i + 1) % validSpgCount); }}
            >
              &gt;
            </button>
            <div className="absolute bottom-1 left-1/2 -translate-x-1/2 flex gap-1">
              {spgUrls.map((_, i) => (
                <span
                  key={i}
                  className={`w-1.5 h-1.5 rounded-full ${i === spgSlideIdx ? 'bg-white' : 'bg-white/40'}`}
                />
              ))}
            </div>
          </>
        )}
      </div>
    </div>
  );
}

// Create triangle SDF image for MapLibre symbol layer
const TRIANGLE_SIZE = 64;

function ensureTriangleImage(map: maplibregl.Map) {
  if (map.hasImage('ship-triangle')) return;
  const s = TRIANGLE_SIZE;
  const canvas = document.createElement('canvas');
  canvas.width = s;
  canvas.height = s;
  const ctx = canvas.getContext('2d')!;
  // Draw upward-pointing triangle (heading 0 = north)
  ctx.beginPath();
  ctx.moveTo(s / 2, 2);          // top center
  ctx.lineTo(s * 0.12, s - 2);   // bottom left
  ctx.lineTo(s / 2, s * 0.62);   // inner notch
  ctx.lineTo(s * 0.88, s - 2);   // bottom right
  ctx.closePath();
  ctx.fillStyle = '#ffffff';
  ctx.fill();
  const imgData = ctx.getImageData(0, 0, s, s);
  map.addImage('ship-triangle', { width: s, height: s, data: new Uint8Array(imgData.data.buffer) }, { sdf: true });
}

// ── Main layer (WebGL symbol rendering — triangles) ──
export function ShipLayer({ ships, militaryOnly, koreanOnly, hoveredMmsi, focusMmsi, onFocusClear }: Props) {
  const { current: map } = useMap();
  const [selectedMmsi, setSelectedMmsi] = useState<string | null>(null);
  const [imageReady, setImageReady] = useState(false);
  const highlightKorean = !!koreanOnly;
  const prevHoveredRef = useRef<string | null>(null);

  // focusMmsi로 외부에서 모달 열기
  useEffect(() => {
    if (focusMmsi) {
      setSelectedMmsi(focusMmsi);
      onFocusClear?.();
    }
  }, [focusMmsi, onFocusClear]);

  const filtered = useMemo(() => {
    let result = ships;
    if (militaryOnly) result = result.filter(s => isMilitary(s.category));
    return result;
  }, [ships, militaryOnly]);

  // Add triangle image to map
  useEffect(() => {
    if (!map) return;
    const m = map.getMap();
    const addIcon = () => {
      try { ensureTriangleImage(m); } catch { /* already added */ }
      setImageReady(true);
    };
    if (m.isStyleLoaded()) { addIcon(); }
    else { m.once('load', addIcon); }
    return () => { m.off('load', addIcon); };
  }, [map]);

  // Build GeoJSON for all ships
  const shipGeoJson = useMemo(() => {
    const features: GeoJSON.Feature[] = filtered.map(ship => ({
      type: 'Feature' as const,
      properties: {
        mmsi: ship.mmsi,
        name: ship.name,
        color: getShipHex(ship),
        size: SIZE_MAP[ship.category] ?? 0.12,
        isMil: isMilitary(ship.category) ? 1 : 0,
        isKorean: ship.flag === 'KR' ? 1 : 0,
        isCheonghae: ship.mmsi === '440001981' ? 1 : 0,
        heading: ship.heading,
      },
      geometry: {
        type: 'Point' as const,
        coordinates: [ship.lng, ship.lat],
      },
    }));
    return { type: 'FeatureCollection' as const, features };
  }, [filtered]);

  // hoveredMmsi 변경 시 feature-state로 hover 표시 (GeoJSON 재생성 없이)
  useEffect(() => {
    if (!map) return;
    const m = map.getMap();
    if (!m.getSource('ships-source')) return;

    if (prevHoveredRef.current != null) {
      try {
        m.removeFeatureState({ source: 'ships-source', id: prevHoveredRef.current });
      } catch { /* source not ready */ }
    }
    if (hoveredMmsi) {
      try {
        m.setFeatureState({ source: 'ships-source', id: hoveredMmsi }, { hovered: true });
      } catch { /* source not ready */ }
    }
    prevHoveredRef.current = hoveredMmsi ?? null;
  }, [map, hoveredMmsi]);

  // Register click and cursor handlers
  useEffect(() => {
    if (!map) return;
    const m = map.getMap();
    const layerId = 'ships-triangles';

    const handleClick = (e: maplibregl.MapLayerMouseEvent) => {
      if (e.features && e.features.length > 0) {
        const mmsi = e.features[0].properties?.mmsi;
        if (mmsi) setSelectedMmsi(mmsi);
      }
    };
    const handleEnter = () => { m.getCanvas().style.cursor = 'pointer'; };
    const handleLeave = () => { m.getCanvas().style.cursor = ''; };

    m.on('click', layerId, handleClick);
    m.on('mouseenter', layerId, handleEnter);
    m.on('mouseleave', layerId, handleLeave);

    return () => {
      m.off('click', layerId, handleClick);
      m.off('mouseenter', layerId, handleEnter);
      m.off('mouseleave', layerId, handleLeave);
    };
  }, [map]);

  const selectedShip = selectedMmsi ? filtered.find(s => s.mmsi === selectedMmsi) ?? null : null;

  // 선단 탐지 (중국어선 선택 시 — 성능 최적화: 근처 선박만 전달)
  const fleet: FleetConnection | null = useMemo(() => {
    if (!selectedShip || selectedShip.flag !== 'CN') return null;
    // 0.2도(~12NM) 이내 선박만 필터링하여 전달
    const nearby = ships.filter(s =>
      Math.abs(s.lat - selectedShip.lat) < 0.2 &&
      Math.abs(s.lng - selectedShip.lng) < 0.2
    );
    return detectFleet(selectedShip, nearby);
  }, [selectedShip, ships]);

  // 선단 연결선 GeoJSON
  const fleetLineGeoJson = useMemo(() => {
    if (!fleet) return { type: 'FeatureCollection' as const, features: [] };
    return {
      type: 'FeatureCollection' as const,
      features: fleet.members.map(m => ({
        type: 'Feature' as const,
        properties: { role: m.role },
        geometry: {
          type: 'LineString' as const,
          coordinates: [
            [fleet.selectedShip.lng, fleet.selectedShip.lat],
            [m.ship.lng, m.ship.lat],
          ],
        },
      })),
    };
  }, [fleet]);

  // Carrier labels — only a few, so DOM markers are fine
  const carriers = useMemo(() => filtered.filter(s => s.category === 'carrier'), [filtered]);



  // 선단 역할별 색상
  const FLEET_ROLE_COLORS: Record<string, string> = {
    pair: '#ef4444',
    carrier: '#f97316',
    lighting: '#eab308',
    mothership: '#dc2626',
    subsidiary: '#6b7280',
  };

  if (!imageReady) return null;

  return (
    <>
      <Source id="ships-source" type="geojson" data={shipGeoJson} promoteId="mmsi">
        {/* Hovered ship highlight ring */}
        <Layer
          id="ships-hover-ring"
          type="circle"
          filter={['boolean', ['feature-state', 'hovered'], false]}
          paint={{
            'circle-radius': 18,
            'circle-color': 'rgba(255, 255, 255, 0.1)',
            'circle-stroke-color': '#ffffff',
            'circle-stroke-width': 2,
            'circle-stroke-opacity': 0.9,
          }}
        />
        {/* Korean ship outer ring — enlarged when highlighted */}
        <Layer
          id="ships-korean-ring"
          type="circle"
          filter={['==', ['get', 'isKorean'], 1]}
          paint={{
            'circle-radius': highlightKorean ? ['*', ['get', 'size'], 22] : ['*', ['get', 'size'], 14],
            'circle-color': highlightKorean ? 'rgba(0, 229, 255, 0.08)' : 'transparent',
            'circle-stroke-color': '#00e5ff',
            'circle-stroke-width': highlightKorean ? 2.5 : 1.5,
            'circle-stroke-opacity': highlightKorean ? 1 : 0.6,
          }}
        />
        {/* Korean ship label — always mounted, visibility으로 제어 */}
        <Layer
          id="ships-korean-label"
          type="symbol"
          filter={['==', ['get', 'isKorean'], 1]}
          layout={{
            'visibility': highlightKorean ? 'visible' : 'none',
            'text-field': ['get', 'name'],
            'text-size': 9,
            'text-offset': [0, 2.2],
            'text-anchor': 'top',
            'text-allow-overlap': false,
            'text-font': ['Open Sans Regular'],
          }}
          paint={{
            'text-color': '#00e5ff',
            'text-halo-color': 'rgba(0,0,0,0.8)',
            'text-halo-width': 1,
          }}
        />
        {/* Main ship triangles */}
        <Layer
          id="ships-triangles"
          type="symbol"
          layout={{
            'icon-image': 'ship-triangle',
            'icon-size': ['get', 'size'],
            'icon-rotate': ['get', 'heading'],
            'icon-rotation-alignment': 'map',
            'icon-allow-overlap': true,
            'icon-ignore-placement': true,
          }}
          paint={{
            'icon-color': ['get', 'color'],
            'icon-opacity': 0.9,
            'icon-halo-color': ['case',
              ['==', ['get', 'isMil'], 1], '#ffffff',
              'rgba(255,255,255,0.3)',
            ],
            'icon-halo-width': ['case',
              ['==', ['get', 'isMil'], 1], 1,
              0.3,
            ],
          }}
        />
      </Source>

      {/* Carrier labels as DOM markers (very few) */}
      {carriers.map(ship => (
        <Marker key={`label-${ship.mmsi}`} longitude={ship.lng} latitude={ship.lat} anchor="center">
          <div style={{ pointerEvents: 'none' }}>
            <div className="gl-marker-label" style={{ color: getShipColor(ship) }}>
              {ship.name}
            </div>
          </div>
        </Marker>
      ))}

      {/* Fleet connection lines — 중국어선 클릭 시만 */}
      {fleet && fleetLineGeoJson.features.length > 0 && selectedShip?.flag === 'CN' && (
        <Source id="fleet-lines" type="geojson" data={fleetLineGeoJson}>
          <Layer
            id="fleet-line-layer"
            type="line"
            paint={{
              'line-color': '#ef4444',
              'line-width': 2,
              'line-dasharray': [3, 2],
              'line-opacity': 0.8,
            }}
          />
        </Source>
      )}

      {/* Fleet member markers — 중국어선 클릭 시만 */}
      {fleet && selectedShip?.flag === 'CN' && fleet.members.map(m => (
        <Marker key={`fleet-${m.ship.mmsi}`} longitude={m.ship.lng} latitude={m.ship.lat} anchor="center">
          <div style={{
            width: 24, height: 24, borderRadius: '50%',
            border: `2px solid ${FLEET_ROLE_COLORS[m.role] || '#ef4444'}`,
            background: 'rgba(0,0,0,0.6)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontSize: 8, color: '#fff', fontWeight: 700,
            filter: `drop-shadow(0 0 4px ${FLEET_ROLE_COLORS[m.role] || '#ef4444'})`,
          }}>
            {m.role === 'pair' ? 'PT' : m.role === 'carrier' ? 'FC' : m.role === 'lighting' ? '灯' : '●'}
          </div>
          <div style={{
            fontSize: 6, color: FLEET_ROLE_COLORS[m.role] || '#888', textAlign: 'center',
            textShadow: '0 0 3px #000', fontWeight: 700, marginTop: -2,
          }}>
            {m.roleKo} {m.distanceNm.toFixed(1)}NM
          </div>
        </Marker>
      ))}

      {/* Popup for selected ship */}
      {selectedShip && (
        <ShipPopup ship={selectedShip} onClose={() => setSelectedMmsi(null)} fleet={fleet} />
      )}
    </>
  );
}

const ShipPopup = memo(function ShipPopup({ ship, onClose, fleet }: { ship: Ship; onClose: () => void; fleet?: FleetConnection | null }) {
  const { t } = useTranslation('ships');
  const mtType = getMTType(ship);
  const color = MT_TYPE_COLORS[mtType] || MT_TYPE_COLORS.unknown;
  const isMil = isMilitary(ship.category);
  const navyLabel = isMil && ship.flag ? t(`navyLabel.${ship.flag}`, { defaultValue: '' }) : undefined;
  const navyAccent = isMil && ship.flag && NAVY_COLORS[ship.flag] ? NAVY_COLORS[ship.flag] : undefined;
  const flagEmoji = ship.flag ? FLAG_EMOJI[ship.flag] || '' : '';

  // Draggable popup
  const popupRef = useRef<HTMLDivElement>(null);
  const dragging = useRef(false);
  const dragOffset = useRef({ x: 0, y: 0 });

  const onMouseDown = useCallback((e: React.MouseEvent) => {
    // Only drag from header area
    const target = e.target as HTMLElement;
    if (!target.closest('.ship-popup-header')) return;
    e.preventDefault();
    dragging.current = true;
    const popupEl = popupRef.current?.closest('.maplibregl-popup') as HTMLElement | null;
    if (!popupEl) return;
    const rect = popupEl.getBoundingClientRect();
    dragOffset.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };
    popupEl.style.transition = 'none';
  }, []);

  useEffect(() => {
    const onMouseMove = (e: MouseEvent) => {
      if (!dragging.current) return;
      const popupEl = popupRef.current?.closest('.maplibregl-popup') as HTMLElement | null;
      if (!popupEl) return;
      // Switch to fixed positioning for free drag
      popupEl.style.transform = 'none';
      popupEl.style.position = 'fixed';
      popupEl.style.left = `${e.clientX - dragOffset.current.x}px`;
      popupEl.style.top = `${e.clientY - dragOffset.current.y}px`;
    };
    const onMouseUp = () => { dragging.current = false; };
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
    return () => {
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    };
  }, []);

  return (
    <Popup longitude={ship.lng} latitude={ship.lat}
      onClose={onClose} closeOnClick={false}
      anchor="bottom" maxWidth="340px" className="gl-popup">
      <div ref={popupRef} className="ship-popup-body" onMouseDown={onMouseDown}>
        {/* Header — draggable handle */}
        <div
          className="ship-popup-header"
          style={{ background: isMil ? '#1a1a2e' : '#1565c0', cursor: 'grab' }}
        >
          {flagEmoji && <span className="text-base leading-none">{flagEmoji}</span>}
          <strong className="ship-popup-name">{ship.name}</strong>
          {navyLabel && (
            <span className="ship-popup-navy-badge" style={{ background: navyAccent || color }}>
              {navyLabel}
            </span>
          )}
        </div>

        {/* Photo */}
        <VesselPhoto mmsi={ship.mmsi} imo={ship.imo} shipImagePath={ship.shipImagePath} shipImageCount={ship.shipImageCount} />

        {/* Type tags */}
        <div className="ship-popup-tags">
          <span className="ship-tag ship-tag-primary" style={{ background: color }}>
            {t(`mtTypeLabel.${mtType}`, { defaultValue: 'Unknown' })}
          </span>
          <span className="ship-tag ship-tag-secondary">
            {t(`categoryLabel.${ship.category}`)}
          </span>
          {ship.typeDesc && (
            <span className="ship-tag ship-tag-dim">{ship.typeDesc}</span>
          )}
        </div>

        {/* Data grid — paired rows */}
        <div className="ship-popup-grid">
          {/* Identity */}
          <div className="ship-popup-row">
            <span className="ship-popup-label">MMSI</span>
            <span className="ship-popup-value">{ship.mmsi}</span>
          </div>
          <div className="ship-popup-row">
            <span className="ship-popup-label">IMO</span>
            <span className="ship-popup-value">{ship.imo || '-'}</span>
          </div>

          {ship.callSign && (
            <>
              <div className="ship-popup-row">
                <span className="ship-popup-label">{t('popup.callSign')}</span>
                <span className="ship-popup-value">{ship.callSign}</span>
              </div>
              <div className="ship-popup-row" />
            </>
          )}

          {/* Position — paired */}
          <div className="ship-popup-row">
            <span className="ship-popup-label">Lat</span>
            <span className="ship-popup-value">{ship.lat.toFixed(4)}</span>
          </div>
          <div className="ship-popup-row">
            <span className="ship-popup-label">Lon</span>
            <span className="ship-popup-value">{ship.lng.toFixed(4)}</span>
          </div>

          {/* Navigation — paired */}
          <div className="ship-popup-row">
            <span className="ship-popup-label">HDG</span>
            <span className="ship-popup-value">{ship.heading.toFixed(1)}&deg;</span>
          </div>
          <div className="ship-popup-row">
            <span className="ship-popup-label">COG</span>
            <span className="ship-popup-value">{ship.course.toFixed(1)}&deg;</span>
          </div>

          <div className="ship-popup-row">
            <span className="ship-popup-label">SOG</span>
            <span className="ship-popup-value">{ship.speed.toFixed(1)} kn</span>
          </div>
          <div className="ship-popup-row">
            <span className="ship-popup-label">Draught</span>
            <span className="ship-popup-value">{ship.draught ? `${ship.draught.toFixed(2)}m` : '-'}</span>
          </div>

          {/* Dimensions — paired */}
          <div className="ship-popup-row">
            <span className="ship-popup-label">Length</span>
            <span className="ship-popup-value">{ship.length ? `${ship.length}m` : '-'}</span>
          </div>
          <div className="ship-popup-row">
            <span className="ship-popup-label">Width</span>
            <span className="ship-popup-value">{ship.width ? `${ship.width}m` : '-'}</span>
          </div>
        </div>

        {/* Long-value fields — full width below grid */}
        {ship.status && (
          <div className="ship-popup-full-row">
            <span className="ship-popup-label">Status</span>
            <span className="ship-popup-value">{ship.status}</span>
          </div>
        )}
        {ship.destination && (
          <div className="ship-popup-full-row">
            <span className="ship-popup-label">Dest</span>
            <span className="ship-popup-value">{ship.destination}</span>
          </div>
        )}
        {ship.eta && (
          <div className="ship-popup-full-row">
            <span className="ship-popup-label">ETA</span>
            <span className="ship-popup-value">{new Date(ship.eta).toLocaleString()}</span>
          </div>
        )}

        {/* Fleet info (중국어선만) */}
        {fleet && fleet.members.length > 0 && (
          <div style={{ borderTop: '1px solid #333', marginTop: 6, paddingTop: 6 }}>
            <div style={{ fontSize: 10, fontWeight: 700, color: '#ef4444', marginBottom: 4 }}>
              🔗 {fleet.fleetTypeKo} — {fleet.members.length}척 연결
            </div>
            {fleet.members.slice(0, 5).map(m => (
              <div key={m.ship.mmsi} style={{ fontSize: 9, display: 'flex', gap: 4, padding: '2px 0', color: '#ccc' }}>
                <span style={{ color: '#ef4444', fontWeight: 700, minWidth: 55 }}>{m.roleKo}</span>
                <span style={{ flex: 1 }}>{m.ship.name || m.ship.mmsi}</span>
                <span style={{ color: '#f97316' }}>{m.distanceNm.toFixed(1)}NM</span>
              </div>
            ))}
            {fleet.members.length > 5 && (
              <div style={{ fontSize: 8, color: '#666' }}>...외 {fleet.members.length - 5}척</div>
            )}
          </div>
        )}

        {/* Footer */}
        <div className="ship-popup-footer">
          <span className="ship-popup-timestamp">
            {t('popup.lastUpdate')}: {new Date(ship.lastSeen).toLocaleString()}
          </span>
          <a href={`https://www.marinetraffic.com/en/ais/details/ships/mmsi:${ship.mmsi}`}
            target="_blank" rel="noopener noreferrer" className="ship-popup-link">
            MarineTraffic &rarr;
          </a>
        </div>
      </div>
    </Popup>
  );
});
