import maplibregl, {
  type LayerSpecification,
  type StyleSpecification,
  type VectorSourceSpecification,
} from 'maplibre-gl';
import type { BaseMapId, BathyZoomRange, MapProjectionId } from '../types';
import { getLayerId, getMapTilerKey } from '../lib/mapCore';

export const SHALLOW_WATER_FILL_DEFAULT = '#14606e';
export const SHALLOW_WATER_LINE_DEFAULT = '#114f5c';

const BATHY_ZOOM_RANGES: BathyZoomRange[] = [
  { id: 'bathymetry-fill', mercator: [3, 24], globe: [3, 24] },
  { id: 'bathymetry-borders-major', mercator: [3, 7], globe: [3, 7] },
  { id: 'bathymetry-borders', mercator: [7, 24], globe: [7, 24] },
  { id: 'bathymetry-lines-coarse', mercator: [5, 7], globe: [5, 7] },
  { id: 'bathymetry-lines-major', mercator: [7, 9], globe: [7, 9] },
  { id: 'bathymetry-lines-detail', mercator: [9, 24], globe: [9, 24] },
  { id: 'bathymetry-labels-coarse', mercator: [6, 9], globe: [6, 9] },
  { id: 'bathymetry-labels', mercator: [9, 24], globe: [9, 24] },
];

/**
 * 줌 기반 LOD — 줌아웃 시 vertex가 폭증하는 육지 레이어의 minzoom을 올려
 * 광역 뷰에서는 생략하고, 줌인 시 자연스럽게 디테일이 나타나도록 함.
 * 해양 서비스 특성상 육지 디테일은 연안 확대 시에만 필요.
 */
function applyLandLayerLOD(style: StyleSpecification): void {
  if (!style.layers || !Array.isArray(style.layers)) return;

  // source-layer → 렌더링을 시작할 최소 줌 레벨
  // globe 모드 줌아웃 시 vertex 65535 초과로 GPU 렌더링 아티팩트(노란 막대) 방지
  const LOD_MINZOOM: Record<string, number> = {
    'landcover': 9,
    'globallandcover': 9,
    'landuse': 11,
    'boundary': 5,
    'transportation': 8,
    'transportation_name': 10,
    'building': 14,
    'housenumber': 16,
    'aeroway': 11,
    'park': 10,
    'mountain_peak': 11,
  };

  for (const layer of style.layers as unknown as LayerSpecification[]) {
    const spec = layer as Record<string, unknown>;
    const sourceLayer = spec['source-layer'] as string | undefined;
    if (!sourceLayer) continue;
    const lodMin = LOD_MINZOOM[sourceLayer];
    if (lodMin === undefined) continue;
    // 기존 minzoom보다 높을 때만 덮어씀
    const current = (spec.minzoom as number) ?? 0;
    if (lodMin > current) {
      spec.minzoom = lodMin;
    }
  }
}

export function injectOceanBathymetryLayers(style: StyleSpecification, maptilerKey: string) {
  const oceanSourceId = 'maptiler-ocean';

  if (!style.sources) style.sources = {} as StyleSpecification['sources'];
  if (!style.layers) style.layers = [];

  if (!style.sources[oceanSourceId]) {
    style.sources[oceanSourceId] = {
      type: 'vector',
      url: `https://api.maptiler.com/tiles/ocean/tiles.json?key=${encodeURIComponent(maptilerKey)}`,
    } satisfies VectorSourceSpecification as unknown as StyleSpecification['sources'][string];
  }

  const depth = ['to-number', ['get', 'depth']] as unknown as number[];
  const depthLabel = ['concat', ['to-string', ['*', depth, -1]], 'm'] as unknown as string[];

  // 수심 색상: 전체 범위 (-8000m ~ 0m)
  const bathyFillColor = [
    'interpolate',
    ['linear'],
    depth,
    -8000,
    '#010610',
    -4000,
    '#030c1c',
    -2000,
    '#041022',
    -1000,
    '#051529',
    -500,
    '#061a30',
    -200,
    '#071f36',
    -100,
    '#08263d',
    -50,
    '#0e3d5e',
    -20,
    '#145578',
    -10,
    '#1a6e8e',
    0,
    '#2097a6',
  ] as const;

  // --- Depth tiers for zoom-based LOD ---
  // 줌 기반 LOD로 vertex 제어 — 줌아웃에선 주요 등심선만, 줌인에서 점진적 디테일
  const DEPTHS_COARSE = [-1000, -2000];
  const DEPTHS_MEDIUM = [-100, -500, -1000, -2000, -4000];
  const DEPTHS_DETAIL = [-50, -100, -200, -500, -1000, -2000, -4000, -8000];
  const depthIn = (depths: number[]) =>
    ['in', depth, ['literal', depths]] as unknown[];

  // === Fill (contour polygons) — 단일 레이어, 전체 depth ===
  const bathyFill: LayerSpecification = {
    id: 'bathymetry-fill',
    type: 'fill',
    source: oceanSourceId,
    'source-layer': 'contour',
    minzoom: 3,
    maxzoom: 24,
    paint: {
      'fill-color': bathyFillColor,
      'fill-opacity': ['interpolate', ['linear'], ['zoom'], 0, 0.9, 5, 0.88, 8, 0.84, 10, 0.78],
    },
  } as unknown as LayerSpecification;

  // === Borders (contour polygon edges) — 2-tier LOD ===
  // z3-z7: 1000m, 2000m 경계만
  const bathyBordersMajor: LayerSpecification = {
    id: 'bathymetry-borders-major',
    type: 'line',
    source: oceanSourceId,
    'source-layer': 'contour',
    minzoom: 3,
    maxzoom: 7,
    filter: depthIn(DEPTHS_COARSE) as unknown as unknown[],
    paint: {
      'line-color': 'rgba(255,255,255,0.14)',
      'line-opacity': ['interpolate', ['linear'], ['zoom'], 3, 0.10, 6, 0.16],
      'line-blur': ['interpolate', ['linear'], ['zoom'], 3, 0.5, 6, 0.35],
      'line-width': ['interpolate', ['linear'], ['zoom'], 3, 0.25, 6, 0.4],
    },
  } as unknown as LayerSpecification;

  // z7+: 전체 등심선 경계
  const bathyBorders: LayerSpecification = {
    id: 'bathymetry-borders',
    type: 'line',
    source: oceanSourceId,
    'source-layer': 'contour',
    minzoom: 7,
    maxzoom: 24,
    paint: {
      'line-color': 'rgba(255,255,255,0.06)',
      'line-opacity': ['interpolate', ['linear'], ['zoom'], 7, 0.18, 12, 0.22],
      'line-blur': ['interpolate', ['linear'], ['zoom'], 7, 0.3, 10, 0.2],
      'line-width': ['interpolate', ['linear'], ['zoom'], 7, 0.35, 12, 0.6],
    },
  } as unknown as LayerSpecification;

  // === Contour lines (contour_line) — 3-tier LOD ===
  // z5-z7: 1000m, 2000m만
  const bathyLinesCoarse: LayerSpecification = {
    id: 'bathymetry-lines-coarse',
    type: 'line',
    source: oceanSourceId,
    'source-layer': 'contour_line',
    minzoom: 5,
    maxzoom: 7,
    filter: depthIn(DEPTHS_COARSE) as unknown as unknown[],
    paint: {
      'line-color': 'rgba(255,255,255,0.12)',
      'line-opacity': ['interpolate', ['linear'], ['zoom'], 5, 0.15, 7, 0.22],
      'line-blur': 0.5,
      'line-width': ['interpolate', ['linear'], ['zoom'], 5, 0.4, 7, 0.6],
    },
  } as unknown as LayerSpecification;

  // z7-z9: 100, 500, 1000, 2000, 4000m
  const bathyLinesMajor: LayerSpecification = {
    id: 'bathymetry-lines-major',
    type: 'line',
    source: oceanSourceId,
    'source-layer': 'contour_line',
    minzoom: 7,
    maxzoom: 9,
    filter: depthIn(DEPTHS_MEDIUM) as unknown as unknown[],
    paint: {
      'line-color': 'rgba(255,255,255,0.16)',
      'line-opacity': ['interpolate', ['linear'], ['zoom'], 7, 0.22, 9, 0.28],
      'line-blur': ['interpolate', ['linear'], ['zoom'], 7, 0.4, 9, 0.2],
      'line-width': ['interpolate', ['linear'], ['zoom'], 7, 0.6, 9, 0.95],
    },
  } as unknown as LayerSpecification;

  // z9+: 50~8000m (풀 디테일)
  const bathyLinesDetail: LayerSpecification = {
    id: 'bathymetry-lines-detail',
    type: 'line',
    source: oceanSourceId,
    'source-layer': 'contour_line',
    minzoom: 9,
    maxzoom: 24,
    filter: depthIn(DEPTHS_DETAIL) as unknown as unknown[],
    paint: {
      'line-color': 'rgba(255,255,255,0.16)',
      'line-opacity': ['interpolate', ['linear'], ['zoom'], 9, 0.28, 12, 0.34],
      'line-blur': ['interpolate', ['linear'], ['zoom'], 9, 0.2, 11, 0.15],
      'line-width': ['interpolate', ['linear'], ['zoom'], 9, 0.95, 12, 1.3],
    },
  } as unknown as LayerSpecification;

  // === Labels — 2-tier LOD ===
  // z6-z9: 1000m, 2000m 라벨만
  const bathyLabelsCoarse: LayerSpecification = {
    id: 'bathymetry-labels-coarse',
    type: 'symbol',
    source: oceanSourceId,
    'source-layer': 'contour_line',
    minzoom: 6,
    maxzoom: 9,
    filter: depthIn(DEPTHS_COARSE) as unknown as unknown[],
    layout: {
      'symbol-placement': 'line',
      'text-field': depthLabel,
      'text-font': ['Noto Sans Regular'],
      'text-size': ['interpolate', ['linear'], ['zoom'], 6, 10, 9, 12],
      'text-allow-overlap': false,
      'text-padding': 4,
      'text-rotation-alignment': 'map',
    },
    paint: {
      'text-color': 'rgba(226,232,240,0.78)',
      'text-halo-color': 'rgba(2,6,23,0.88)',
      'text-halo-width': 1.2,
      'text-halo-blur': 0.5,
    },
  } as unknown as LayerSpecification;

  // z9+: 100~4000m 라벨
  const bathyLabels: LayerSpecification = {
    id: 'bathymetry-labels',
    type: 'symbol',
    source: oceanSourceId,
    'source-layer': 'contour_line',
    minzoom: 9,
    filter: depthIn(DEPTHS_MEDIUM) as unknown as unknown[],
    layout: {
      'symbol-placement': 'line',
      'text-field': depthLabel,
      'text-font': ['Noto Sans Regular'],
      'text-size': ['interpolate', ['linear'], ['zoom'], 9, 12, 11, 14, 13, 16],
      'text-allow-overlap': false,
      'text-padding': 4,
      'text-rotation-alignment': 'map',
    },
    paint: {
      'text-color': 'rgba(226,232,240,0.78)',
      'text-halo-color': 'rgba(2,6,23,0.88)',
      'text-halo-width': 1.2,
      'text-halo-blur': 0.5,
    },
  } as unknown as LayerSpecification;

  const landformLabels: LayerSpecification = {
    id: 'bathymetry-landforms',
    type: 'symbol',
    source: oceanSourceId,
    'source-layer': 'landform',
    minzoom: 6,
    filter: ['has', 'name'] as unknown as unknown[],
    layout: {
      'text-field': ['get', 'name'] as unknown as unknown[],
      'text-font': ['Noto Sans Regular'],
      'text-size': ['interpolate', ['linear'], ['zoom'], 6, 10, 8, 12, 10, 13, 12, 14],
      'text-allow-overlap': false,
      'text-anchor': 'center',
      'text-offset': [0, 0.0],
    },
    paint: {
      'text-color': 'rgba(148,163,184,0.75)',
      'text-halo-color': 'rgba(2,6,23,0.88)',
      'text-halo-width': 1.2,
      'text-halo-blur': 0.6,
    },
  } as unknown as LayerSpecification;

  const layers = Array.isArray(style.layers) ? (style.layers as unknown as LayerSpecification[]) : [];
  if (!Array.isArray(style.layers)) {
    style.layers = layers as unknown as StyleSpecification['layers'];
  }

  // Brighten base-map water fills so shallow coasts, rivers & lakes blend naturally
  // with the bathymetry gradient instead of appearing as near-black voids.
  const waterRegex = /(water|sea|ocean|river|lake|coast|bay)/i;
  const SHALLOW_WATER_FILL = SHALLOW_WATER_FILL_DEFAULT;
  const SHALLOW_WATER_LINE = SHALLOW_WATER_LINE_DEFAULT;
  for (const layer of layers) {
    const id = getLayerId(layer);
    if (!id) continue;
    const spec = layer as Record<string, unknown>;
    const sourceLayer = String(spec['source-layer'] ?? '').toLowerCase();
    const layerType = String(spec.type ?? '');
    const isWater = waterRegex.test(id) || waterRegex.test(sourceLayer);
    if (!isWater) continue;

    const paint = (spec.paint ?? {}) as Record<string, unknown>;
    if (layerType === 'fill') {
      paint['fill-color'] = SHALLOW_WATER_FILL;
      spec.paint = paint;
    } else if (layerType === 'line') {
      paint['line-color'] = SHALLOW_WATER_LINE;
      spec.paint = paint;
    }
  }

  const symbolIndex = layers.findIndex((l) => (l as { type?: unknown } | null)?.type === 'symbol');
  const insertAt = symbolIndex >= 0 ? symbolIndex : layers.length;

  const existingIds = new Set<string>();
  for (const layer of layers) {
    const id = getLayerId(layer);
    if (id) existingIds.add(id);
  }

  const toInsert = [
    bathyFill,
    bathyBordersMajor,
    bathyBorders,
    bathyLinesCoarse,
    bathyLinesMajor,
    bathyLinesDetail,
    bathyLabelsCoarse,
    bathyLabels,
    landformLabels,
  ].filter((l) => !existingIds.has(l.id));
  if (toInsert.length > 0) layers.splice(insertAt, 0, ...toInsert);
}

export function applyBathymetryZoomProfile(map: maplibregl.Map, baseMap: BaseMapId, projection: MapProjectionId) {
  if (!map || !map.isStyleLoaded()) return;
  if (baseMap !== 'enhanced') return;
  const isGlobe = projection === 'globe';

  for (const range of BATHY_ZOOM_RANGES) {
    if (!map.getLayer(range.id)) continue;
    const [minzoom, maxzoom] = isGlobe ? range.globe : range.mercator;
    try {
      map.setLayoutProperty(range.id, 'visibility', 'visible');
    } catch {
      // ignore
    }
    try {
      map.setLayerZoomRange(range.id, minzoom, maxzoom);
    } catch {
      // ignore
    }
  }

}

function applyKoreanLabels(style: StyleSpecification) {
  if (!style.layers) return;
  const koTextField = ['coalesce', ['get', 'name:ko'], ['get', 'name']];
  for (const layer of style.layers as unknown as LayerSpecification[]) {
    if ((layer as { type?: string }).type !== 'symbol') continue;
    const layout = (layer as Record<string, unknown>).layout as
      | Record<string, unknown>
      | undefined;
    if (!layout?.['text-field']) continue;
    layout['text-field'] = koTextField;
  }
}

export async function resolveInitialMapStyle(signal: AbortSignal): Promise<string | StyleSpecification> {
  const key = getMapTilerKey();
  if (!key) return '/map/styles/osm-seamark.json';

  const baseMapId = (import.meta.env.VITE_MAPTILER_BASE_MAP_ID || 'dataviz-dark').trim();
  const styleUrl = `https://api.maptiler.com/maps/${encodeURIComponent(baseMapId)}/style.json?key=${encodeURIComponent(key)}`;

  const res = await fetch(styleUrl, { signal, headers: { accept: 'application/json' } });
  if (!res.ok) throw new Error(`MapTiler style fetch failed: ${res.status} ${res.statusText}`);
  const json = (await res.json()) as StyleSpecification;
  applyLandLayerLOD(json);
  applyKoreanLabels(json);
  injectOceanBathymetryLayers(json, key);
  return json;
}

export async function resolveMapStyle(baseMap: BaseMapId, signal: AbortSignal): Promise<string | StyleSpecification> {
  if (baseMap === 'ocean') {
    const { resolveOceanStyle } = await import('../../../features/oceanMap/lib/resolveOceanStyle');
    return resolveOceanStyle(signal);
  }
  if (baseMap === 'enc') {
    const { fetchEncStyle } = await import('../../../features/encMap/lib/encStyle');
    return fetchEncStyle(signal);
  }
  // 레거시 베이스맵 비활성 — 향후 위성/라이트 테마 등 추가 시 재활용
  // if (baseMap === 'legacy') return '/map/styles/carto-dark.json';
  void baseMap;
  return resolveInitialMapStyle(signal);
}
