/**
 * HNS 대기확산 결과(rsltData)를 deck.gl 레이어로 변환하는 유틸리티
 *
 * - rsltData에 저장된 inputParams + coord + weather 로 확산 엔진 재실행
 * - MapView와 동일한 BitmapLayer (캔버스 히트맵) + ScatterplotLayer (AEGL 원) 생성
 */
import { BitmapLayer, ScatterplotLayer } from '@deck.gl/layers';
import { computeDispersion } from '@components/hns/utils/dispersionEngine';
import { getSubstanceToxicity } from '@components/hns/utils/toxicityData';
import { hexToRgba } from '@components/common/map/mapUtils';
import type { HnsAnalysisItem } from '@interfaces/hns/HnsInterface';
import type {
  MeteoParams,
  SourceParams,
  SimParams,
} from '@interfaces/hns/HnsInterface';
import type {
  DispersionModel,
  AlgorithmType,
  StabilityClass,
} from '@/types/hns/HnsType';

// MapView와 동일한 색상 정지점
const COLOR_STOPS: [number, number, number, number][] = [
  [34, 197, 94, 220],   // green  (저농도)
  [234, 179, 8, 235],   // yellow
  [249, 115, 22, 245],  // orange
  [239, 68, 68, 250],   // red    (고농도)
  [185, 28, 28, 255],   // dark red (초고농도)
];

/** rsltData.weather → MeteoParams 변환 */
function toMeteo(weather: Record<string, unknown>): MeteoParams {
  return {
    windSpeed: (weather.windSpeed as number) ?? 5.0,
    windDirDeg: (weather.windDirection as number) ?? 270,
    stability: ((weather.stability as string) ?? 'D') as StabilityClass,
    temperature: ((weather.temperature as number) ?? 15) + 273.15,
    pressure: 101325,
    mixingHeight: 800,
  };
}

/** rsltData.inputParams + toxicity → SourceParams 변환 */
function toSource(
  inputParams: Record<string, unknown>,
  tox: ReturnType<typeof getSubstanceToxicity>,
): SourceParams {
  return {
    Q: (inputParams.emissionRate as number) ?? tox.Q,
    QTotal: (inputParams.totalRelease as number) ?? tox.QTotal,
    x0: 0,
    y0: 0,
    z0: (inputParams.releaseHeight as number) ?? 0.5,
    releaseDuration:
      inputParams.releaseType === '연속 유출'
        ? ((inputParams.releaseDuration as number) ?? 300)
        : 0,
    molecularWeight: tox.mw,
    vaporPressure: tox.vaporPressure,
    densityGas: tox.densityGas,
    poolRadius: (inputParams.poolRadius as number) ?? tox.poolRadius,
  };
}

const SIM_PARAMS: SimParams = {
  xRange: [-100, 10000],
  yRange: [-2000, 2000],
  nx: 300,
  ny: 200,
  zRef: 1.5,
  tStart: 0,
  tEnd: 600,
  dt: 30,
};

/** 농도 포인트 배열 → 캔버스 BitmapLayer */
function buildBitmapLayer(
  id: string,
  points: Array<{ lon: number; lat: number; concentration: number }>,
  visible: boolean,
): BitmapLayer | null {
  const filtered = points.filter((p) => p.concentration > 0.01);
  if (filtered.length === 0) return null;

  const maxConc = Math.max(...points.map((p) => p.concentration));
  const minConc = Math.min(...filtered.map((p) => p.concentration));
  const logMin = Math.log(minConc);
  const logMax = Math.log(maxConc);
  const logRange = logMax - logMin || 1;

  let minLon = Infinity, maxLon = -Infinity, minLat = Infinity, maxLat = -Infinity;
  for (const p of points) {
    if (p.lon < minLon) minLon = p.lon;
    if (p.lon > maxLon) maxLon = p.lon;
    if (p.lat < minLat) minLat = p.lat;
    if (p.lat > maxLat) maxLat = p.lat;
  }
  const padLon = (maxLon - minLon) * 0.02;
  const padLat = (maxLat - minLat) * 0.02;
  minLon -= padLon; maxLon += padLon;
  minLat -= padLat; maxLat += padLat;

  const W = 1200, H = 960;
  const canvas = document.createElement('canvas');
  canvas.width = W;
  canvas.height = H;
  const ctx = canvas.getContext('2d')!;
  ctx.clearRect(0, 0, W, H);

  for (const p of filtered) {
    const ratio = Math.max(0, Math.min(1, (Math.log(p.concentration) - logMin) / logRange));
    const t = ratio * (COLOR_STOPS.length - 1);
    const lo = Math.floor(t);
    const hi = Math.min(lo + 1, COLOR_STOPS.length - 1);
    const f = t - lo;
    const r = Math.round(COLOR_STOPS[lo][0] + (COLOR_STOPS[hi][0] - COLOR_STOPS[lo][0]) * f);
    const g = Math.round(COLOR_STOPS[lo][1] + (COLOR_STOPS[hi][1] - COLOR_STOPS[lo][1]) * f);
    const b = Math.round(COLOR_STOPS[lo][2] + (COLOR_STOPS[hi][2] - COLOR_STOPS[lo][2]) * f);
    const a = (COLOR_STOPS[lo][3] + (COLOR_STOPS[hi][3] - COLOR_STOPS[lo][3]) * f) / 255;

    const px = ((p.lon - minLon) / (maxLon - minLon)) * W;
    const py = (1 - (p.lat - minLat) / (maxLat - minLat)) * H;

    ctx.fillStyle = `rgba(${r},${g},${b},${a.toFixed(2)})`;
    ctx.beginPath();
    ctx.arc(px, py, 6, 0, Math.PI * 2);
    ctx.fill();
  }

  const imageUrl = canvas.toDataURL('image/png');
  return new BitmapLayer({
    id,
    image: imageUrl,
    bounds: [minLon, minLat, maxLon, maxLat],
    opacity: 1.0,
    pickable: false,
    visible,
  });
}

/**
 * HnsAnalysisItem[] → deck.gl 레이어 배열 (BitmapLayer + ScatterplotLayer)
 *
 * IncidentsView의 useMemo 에서 사용
 */
export function buildHnsDispersionLayers(
  analyses: HnsAnalysisItem[],
  visible: boolean = true,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
): any[] {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const layers: any[] = [];

  for (const analysis of analyses) {
    const rslt = analysis.rsltData;
    if (!rslt) continue;

    const coord = rslt.coord as { lon: number; lat: number } | undefined;
    const inputParams = rslt.inputParams as Record<string, unknown> | undefined;
    const weather = rslt.weather as Record<string, unknown> | undefined;
    const zones = rslt.zones as
      | Array<{ level: string; color: string; radius: number; angle: number }>
      | undefined;

    if (!coord || !inputParams || !weather) continue;

    // ── 1. 확산 엔진 재실행 ──────────────────────────
    const substanceName = (inputParams.substance as string) ?? '톨루엔 (Toluene)';
    const tox = getSubstanceToxicity(substanceName);
    const meteo = toMeteo(weather);
    const source = toSource(inputParams, tox);

    const releaseType = (inputParams.releaseType as string) ?? '연속 유출';
    const modelType: DispersionModel =
      releaseType === '연속 유출' ? 'plume'
      : releaseType === '순간 유출' ? 'puff'
      : 'dense_gas';

    const algo = ((inputParams.algorithm as string) ?? 'ALOHA (EPA)') as AlgorithmType;

    let points: Array<{ lon: number; lat: number; concentration: number }> = [];
    try {
      const result = computeDispersion({
        meteo,
        source,
        sim: SIM_PARAMS,
        modelType,
        originLon: coord.lon,
        originLat: coord.lat,
        substanceName,
        t: SIM_PARAMS.dt,
        algorithm: algo,
      });
      points = result.points;
    } catch {
      // 재계산 실패 시 히트맵 생략, 원 레이어만 표출
    }

    // ── 2. BitmapLayer (히트맵 콘) ────────────────────
    if (points.length > 0) {
      const bitmapLayer = buildBitmapLayer(
        `hns-bitmap-${analysis.hnsAnlysSn}`,
        points,
        visible,
      );
      if (bitmapLayer) layers.push(bitmapLayer);
    }

    // ── 3. ScatterplotLayer (AEGL 원) ─────────────────
    if (zones?.length) {
      const zoneData = zones
        .filter((z) => z.radius > 0)
        .map((zone, idx) => ({
          position: [coord.lon, coord.lat] as [number, number],
          radius: zone.radius,
          fillColor: hexToRgba(zone.color, 40) as [number, number, number, number],
          lineColor: hexToRgba(zone.color, 200) as [number, number, number, number],
          level: zone.level,
          idx,
        }));

      if (zoneData.length > 0) {
        layers.push(
          new ScatterplotLayer({
            id: `hns-zones-${analysis.hnsAnlysSn}`,
            data: zoneData,
            getPosition: (d: (typeof zoneData)[0]) => d.position,
            getRadius: (d: (typeof zoneData)[0]) => d.radius,
            getFillColor: (d: (typeof zoneData)[0]) => d.fillColor,
            getLineColor: (d: (typeof zoneData)[0]) => d.lineColor,
            getLineWidth: 2,
            stroked: true,
            radiusUnits: 'meters' as const,
            pickable: false,
            visible,
          }),
        );
      }
    }
  }

  return layers;
}
