import {
  useState,
  useMemo,
  useCallback,
  useEffect,
  type MutableRefObject,
  type ReactNode,
} from 'react';
import { Map, useMap } from '@vis.gl/react-maplibre';
import type { MapLayerMouseEvent } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { useBaseMapStyle } from '@common/hooks/useBaseMapStyle';
import { useMapStore } from '@common/store/mapStore';
import { useMeasureTool } from '@common/hooks/useMeasureTool';
import { S57EncOverlay } from './S57EncOverlay';
import { MeasureOverlay } from './MeasureOverlay';
import { DeckGLOverlay } from './DeckGLOverlay';
import { buildMeasureLayers } from './measureLayers';

const DEFAULT_CENTER: [number, number] = [37.39, 126.64];
const DEFAULT_ZOOM = 10;

export interface BaseMapProps {
  /** 초기 중심 좌표 [lat, lng]. 기본: 인천 송도 */
  center?: [number, number];
  /** 초기 줌 레벨. 기본: 10 */
  zoom?: number;
  /** 지도 클릭 핸들러 (측정 모드 중에는 호출되지 않음) */
  onMapClick?: (lon: number, lat: number) => void;
  /** 줌 변경 핸들러. ScatMap 등 줌 기반 레이어 스케일 조정에 사용 */
  onZoom?: (zoom: number) => void;
  /** 커서 스타일 (예: 'crosshair'). 기본: 'grab' */
  cursor?: string;
  /** false 시 컨트롤 UI·좌표 표시를 숨김 (캡처 전용 모드). 기본: true */
  showOverlays?: boolean;
  /** 지도 캡처 함수 ref (Reports 탭 전용) */
  mapCaptureRef?: MutableRefObject<(() => Promise<string | null>) | null>;
  /** 탭별 고유 오버레이·마커·팝업 등 */
  children?: ReactNode;
}

// ─── 3D 모드 pitch/bearing 제어 ────────────────────────────────────────────
function MapPitchController({ threeD }: { threeD: boolean }) {
  const { current: map } = useMap();
  useEffect(() => {
    if (!map) return;
    map.easeTo(
      threeD ? { pitch: 45, bearing: -17, duration: 800 } : { pitch: 0, bearing: 0, duration: 800 },
    );
  }, [threeD, map]);
  return null;
}

// ─── 지도 캡처 지원 ────────────────────────────────────────────────────────
function MapCaptureSetup({
  captureRef,
}: {
  captureRef: MutableRefObject<(() => Promise<string | null>) | null>;
}) {
  const { current: map } = useMap();
  useEffect(() => {
    if (!map) return;
    captureRef.current = () =>
      new Promise<string | null>((resolve) => {
        map.once('render', () => {
          try {
            const src = map.getCanvas();
            const maxW = 1200;
            const scale = src.width > maxW ? maxW / src.width : 1;
            const composite = document.createElement('canvas');
            composite.width = Math.round(src.width * scale);
            composite.height = Math.round(src.height * scale);
            const ctx = composite.getContext('2d')!;
            ctx.fillStyle = '#0f1117';
            ctx.fillRect(0, 0, composite.width, composite.height);
            ctx.drawImage(src, 0, 0, composite.width, composite.height);
            resolve(composite.toDataURL('image/jpeg', 0.82));
          } catch {
            resolve(null);
          }
        });
        map.triggerRepaint();
      });
  }, [map, captureRef]);
  return null;
}

// ─── 공통 컨트롤 UI + 좌표 표시 ───────────────────────────────────────────
// Map 내부에 렌더링되어 useMap()으로 인스턴스에 접근함.
// 줌 버튼·지도 타입·측정 도구·좌표 표시를 하나의 컴포넌트로 통합.
function MapOverlayControls({
  initialCenter,
  initialZoom,
}: {
  initialCenter: [number, number];
  initialZoom: number;
}) {
  const { current: map } = useMap();
  const mapToggles = useMapStore((s) => s.mapToggles);
  const toggleMap = useMapStore((s) => s.toggleMap);
  const measureMode = useMapStore((s) => s.measureMode);
  const setMeasureMode = useMapStore((s) => s.setMeasureMode);

  const [pos, setPos] = useState({
    lat: initialCenter[0],
    lng: initialCenter[1],
    zoom: initialZoom,
  });

  useEffect(() => {
    if (!map) return;
    const update = () => {
      const c = map.getCenter();
      setPos({ lat: c.lat, lng: c.lng, zoom: map.getZoom() });
    };
    update();
    map.on('move', update);
    map.on('zoom', update);
    return () => {
      map.off('move', update);
      map.off('zoom', update);
    };
  }, [map]);

  const btn =
    'w-[28px] h-[28px] bg-[color-mix(in_srgb,var(--bg-elevated)_85%,transparent)] ' +
    'backdrop-blur-sm border border-stroke rounded-sm text-fg-sub flex items-center justify-center ' +
    'hover:bg-bg-surface-hover hover:text-fg transition-all text-caption select-none cursor-pointer';
  const btnOn = 'text-color-accent border-color-accent bg-[rgba(6,182,212,0.08)]';

  // 좌표·축척 계산
  const { lat, lng, zoom } = pos;
  const latDir = lat >= 0 ? 'N' : 'S';
  const lngDir = lng >= 0 ? 'E' : 'W';
  const mpp = (40075016.686 * Math.cos((lat * Math.PI) / 180)) / (256 * Math.pow(2, zoom));
  const sr = Math.round(mpp * (96 / 0.0254));
  const scaleLabel =
    sr >= 1_000_000 ? `1:${(sr / 1_000_000).toFixed(1)}M` : `1:${sr.toLocaleString()}`;

  return (
    <>
      {/* 좌측 컨트롤 컬럼 */}
      <div className="absolute top-[80px] left-[10px] z-10 flex flex-col gap-1">
        {/* 줌 */}
        <button title="줌 인" onClick={() => map?.zoomIn()} className={btn}>
          +
        </button>
        <button title="줌 아웃" onClick={() => map?.zoomOut()} className={btn}>
          −
        </button>
        <button
          title="초기 위치로"
          onClick={() =>
            map?.flyTo({
              center: [initialCenter[1], initialCenter[0]],
              zoom: initialZoom,
              duration: 1000,
            })
          }
          className={btn}
          style={{ fontSize: '10px' }}
        >
          ⊙
        </button>

        <div className="h-px bg-stroke my-0.5" />

        {/* 지도 타입 */}
        <button
          title="3D 위성 모드"
          onClick={() => toggleMap('threeD')}
          className={`${btn} ${mapToggles.threeD ? btnOn : ''}`}
          style={{ fontSize: '9px', fontWeight: 600, letterSpacing: '-0.3px' }}
        >
          3D
        </button>
        <button
          title="ENC 전자해도"
          onClick={() => toggleMap('s57')}
          className={`${btn} ${mapToggles.s57 ? btnOn : ''}`}
          style={{ fontSize: '8px', fontWeight: 600 }}
        >
          ENC
        </button>

        <div className="h-px bg-stroke my-0.5" />

        {/* 측정 도구 */}
        <button
          title="거리 측정"
          onClick={() => setMeasureMode(measureMode === 'distance' ? null : 'distance')}
          className={`${btn} ${measureMode === 'distance' ? btnOn : ''}`}
          style={{ fontSize: '12px' }}
        >
          📏
        </button>
        <button
          title="면적 측정"
          onClick={() => setMeasureMode(measureMode === 'area' ? null : 'area')}
          className={`${btn} ${measureMode === 'area' ? btnOn : ''}`}
          style={{ fontSize: '11px' }}
        >
          ⬜
        </button>
      </div>

      {/* 좌표 표시 (좌하단) */}
      <div className="cod">
        <span>
          위도{' '}
          <span className="cov">
            {Math.abs(lat).toFixed(4)}°{latDir}
          </span>
        </span>
        <span>
          경도{' '}
          <span className="cov">
            {Math.abs(lng).toFixed(4)}°{lngDir}
          </span>
        </span>
        <span>
          축척 <span className="cov">{scaleLabel}</span>
        </span>
      </div>
    </>
  );
}

// ─── BaseMap ───────────────────────────────────────────────────────────────
export function BaseMap({
  center = DEFAULT_CENTER,
  zoom = DEFAULT_ZOOM,
  onMapClick,
  onZoom,
  cursor,
  showOverlays = true,
  mapCaptureRef,
  children,
}: BaseMapProps) {
  const mapStyle = useBaseMapStyle();
  const mapToggles = useMapStore((s) => s.mapToggles);
  const measureMode = useMapStore((s) => s.measureMode);
  const measureInProgress = useMapStore((s) => s.measureInProgress);
  const measurements = useMapStore((s) => s.measurements);
  const { handleMeasureClick } = useMeasureTool();

  const handleClick = useCallback(
    (e: MapLayerMouseEvent) => {
      const { lng, lat } = e.lngLat;
      if (measureMode !== null) {
        handleMeasureClick(lng, lat);
        return;
      }
      onMapClick?.(lng, lat);
    },
    [measureMode, handleMeasureClick, onMapClick],
  );

  const handleZoom = useCallback(
    (e: { viewState: { zoom: number } }) => {
      onZoom?.(e.viewState.zoom);
    },
    [onZoom],
  );

  const measureDeckLayers = useMemo(
    () => buildMeasureLayers(measureInProgress, measureMode, measurements),
    [measureInProgress, measureMode, measurements],
  );

  return (
    <div className="w-full h-full relative">
      <Map
        initialViewState={{ longitude: center[1], latitude: center[0], zoom }}
        mapStyle={mapStyle}
        className="w-full h-full"
        onClick={handleClick}
        onZoom={handleZoom}
        style={{ cursor: cursor ?? 'grab' }}
        attributionControl={false}
        preserveDrawingBuffer={true}
      >
        {/* 공통 오버레이 */}
        <S57EncOverlay visible={mapToggles.s57 ?? false} />
        <MapPitchController threeD={mapToggles.threeD ?? false} />
        <DeckGLOverlay layers={measureDeckLayers} />
        <MeasureOverlay />
        {mapCaptureRef && <MapCaptureSetup captureRef={mapCaptureRef} />}

        {/* 공통 컨트롤 UI (줌·지도 타입·측정·좌표) */}
        {showOverlays && <MapOverlayControls initialCenter={center} initialZoom={zoom} />}

        {/* 탭별 주입 */}
        {children}
      </Map>

      {/* 측정 모드 힌트 */}
      {showOverlays && measureMode === 'distance' && (
        <div className="boom-drawing-indicator">
          거리 재기 — {measureInProgress.length === 0 ? '시작점을 클릭하세요' : '끝점을 클릭하세요'}
        </div>
      )}
      {showOverlays && measureMode === 'area' && (
        <div className="boom-drawing-indicator">
          면적 재기 — 꼭짓점을 클릭하세요 ({measureInProgress.length}개)
          {measureInProgress.length >= 3 && ' → 첫 번째 점 근처를 클릭하면 닫힙니다'}
        </div>
      )}
    </div>
  );
}
