import { useEffect, useRef, type MutableRefObject } from 'react';
import maplibregl from 'maplibre-gl';
import type { OceanMapSettings, OceanDepthStop, OceanDepthLabelSize, OceanLabelLanguage } from '../model/types';
import type { BaseMapId } from '../../../widgets/map3d/types';
import { kickRepaint, onMapStyleReady } from '../../../widgets/map3d/lib/mapCore';
import { discoverOceanLayers } from '../lib/oceanLayerIds';

/* ── Depth font size presets ──────────────────────────────────────── */
const OCEAN_DEPTH_FONT_SIZE: Record<OceanDepthLabelSize, unknown[]> = {
  small: ['interpolate', ['linear'], ['zoom'], 5, 8, 8, 10, 11, 12],
  medium: ['interpolate', ['linear'], ['zoom'], 5, 10, 8, 12, 11, 15],
  large: ['interpolate', ['linear'], ['zoom'], 5, 12, 8, 15, 11, 18],
};

/* ── Original paint cache (Ocean 네이티브 색상 복원용) ─────────── */
const originalDepthPaint = new Map<string, { fillColor: unknown; fillOpacity: unknown }>();

function captureOriginalDepthPaint(map: maplibregl.Map, layers: string[]) {
  if (originalDepthPaint.size > 0) return; // 이미 캡처됨
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      originalDepthPaint.set(id, {
        fillColor: map.getPaintProperty(id, 'fill-color'),
        fillOpacity: map.getPaintProperty(id, 'fill-opacity'),
      });
    } catch { /* ignore */ }
  }
}

function restoreOriginalDepthPaint(map: maplibregl.Map, layers: string[]) {
  for (const id of layers) {
    const orig = originalDepthPaint.get(id);
    if (!orig || !map.getLayer(id)) continue;
    try {
      map.setPaintProperty(id, 'fill-color', orig.fillColor as never);
      map.setPaintProperty(id, 'fill-opacity', orig.fillOpacity as never);
    } catch { /* ignore */ }
  }
}

/* ── Apply functions (Ocean 전용 — enhanced 코드와 공유 없음) ────── */

function applyOceanDepthColors(map: maplibregl.Map, layers: string[], stops: OceanDepthStop[], opacity: number) {
  if (layers.length === 0) return;
  const sorted = [...stops].sort((a, b) => a.depth - b.depth);

  if (sorted.length < 2) {
    // depthStops 비어있음 → Ocean 네이티브 색상 복원
    restoreOriginalDepthPaint(map, layers);
    return;
  }

  const depth = ['to-number', ['get', 'depth']];
  const expr: unknown[] = ['interpolate', ['linear'], depth];
  for (const s of sorted) {
    expr.push(s.depth, s.color);
  }

  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setPaintProperty(id, 'fill-color', expr as never);
      map.setPaintProperty(id, 'fill-opacity', opacity);
    } catch {
      // ignore
    }
  }
}

function applyOceanContourStyle(
  map: maplibregl.Map,
  layers: string[],
  visible: boolean,
  color: string,
  opacity: number,
  width: number,
) {
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setLayoutProperty(id, 'visibility', visible ? 'visible' : 'none');
      if (visible) {
        map.setPaintProperty(id, 'line-color', color);
        map.setPaintProperty(id, 'line-opacity', opacity);
        map.setPaintProperty(id, 'line-width', width);
      }
    } catch {
      // ignore
    }
  }
}

function applyOceanDepthLabels(
  map: maplibregl.Map,
  layers: string[],
  visible: boolean,
  color: string,
  size: OceanDepthLabelSize,
) {
  const sizeExpr = OCEAN_DEPTH_FONT_SIZE[size];
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setLayoutProperty(id, 'visibility', visible ? 'visible' : 'none');
      if (visible) {
        map.setPaintProperty(id, 'text-color', color);
        map.setLayoutProperty(id, 'text-size', sizeExpr);
      }
    } catch {
      // ignore
    }
  }
}

function applyOceanHillshade(
  map: maplibregl.Map,
  layers: string[],
  visible: boolean,
  exaggeration: number,
  color: string,
) {
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setLayoutProperty(id, 'visibility', visible ? 'visible' : 'none');
      if (visible) {
        map.setPaintProperty(id, 'hillshade-exaggeration', exaggeration);
        map.setPaintProperty(id, 'hillshade-shadow-color', color);
      }
    } catch {
      // ignore
    }
  }
}

function applyOceanLandformLabels(
  map: maplibregl.Map,
  layers: string[],
  visible: boolean,
  color: string,
) {
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setLayoutProperty(id, 'visibility', visible ? 'visible' : 'none');
      if (visible) {
        map.setPaintProperty(id, 'text-color', color);
      }
    } catch {
      // ignore
    }
  }
}

function applyOceanBackground(map: maplibregl.Map, layers: string[], color: string) {
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setPaintProperty(id, 'background-color', color);
    } catch {
      // ignore
    }
  }
  try {
    map.getCanvas().style.background = color;
  } catch {
    // ignore
  }
}

function applyOceanLabelLanguage(map: maplibregl.Map, layers: string[], lang: OceanLabelLanguage) {
  const textField =
    lang === 'local'
      ? ['get', 'name']
      : ['coalesce', ['get', `name:${lang}`], ['get', 'name']];
  for (const id of layers) {
    if (!map.getLayer(id)) continue;
    try {
      map.setLayoutProperty(id, 'text-field', textField);
    } catch {
      // ignore
    }
  }
}

/* ── Hook ──────────────────────────────────────────────────────────── */
export function useOceanMapSettings(
  mapRef: MutableRefObject<maplibregl.Map | null>,
  settings: OceanMapSettings | undefined,
  opts: { baseMap: BaseMapId; mapSyncEpoch: number },
) {
  const settingsRef = useRef(settings);
  useEffect(() => {
    settingsRef.current = settings;
  });

  const { baseMap, mapSyncEpoch } = opts;

  useEffect(() => {
    // Ocean 전용 — enhanced 모드에서는 즉시 return
    if (baseMap !== 'ocean') return;

    const map = mapRef.current;
    const s = settingsRef.current;
    if (!map || !s) return;

    const stop = onMapStyleReady(map, () => {
      const oceanLayers = discoverOceanLayers(map);

      // 커스텀 적용 전에 원본 paint 캡처 (최초 1회)
      captureOriginalDepthPaint(map, oceanLayers.depthFill);

      applyOceanDepthColors(map, oceanLayers.depthFill, s.depthStops, s.depthOpacity);
      applyOceanContourStyle(map, oceanLayers.contourLine, s.contourVisible, s.contourColor, s.contourOpacity, s.contourWidth);
      applyOceanDepthLabels(map, oceanLayers.depthLabel, s.depthLabelsVisible, s.depthLabelColor, s.depthLabelSize);
      applyOceanHillshade(map, oceanLayers.hillshade, s.hillshadeVisible, s.hillshadeExaggeration, s.hillshadeColor);
      applyOceanLandformLabels(map, oceanLayers.landformLabel, s.landformLabelsVisible, s.landformLabelColor);
      applyOceanBackground(map, oceanLayers.background, s.backgroundColor);
      applyOceanLabelLanguage(map, oceanLayers.allSymbol, s.labelLanguage);

      kickRepaint(map);
    });

    return () => stop();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [settings, baseMap, mapSyncEpoch]);
}
