/**
 * KML 표고(DEM) 파생 파일 생성 — `<이름>_byDem.kml`
 *
 * 폴더 로드 시 측점/지장물 KML 의 좌표 고도 성분이 없거나 0 이면, DEM(서버 /api/elevation
 * 프록시 → SRTM 30m, 폴백 90m)으로 지면 표고를 조회해 채운 `<이름>_byDem.kml` 을 만들어
 * PC 로 다운로드한다. 사용자가 받은 파일을 영상 폴더에 넣으면, 로더(parseKmz)가
 * 원본 대신 _byDem 버전을 읽는다(중복 파싱 방지 규칙).
 *
 * - 이미 표고가 있는 좌표(>0)는 그대로 두고 없는 것만 채운다
 * - 폴더에 `<이름>_byDem.kml` 이 이미 있으면 해당 원본은 건너뜀
 * - DEM 조회는 100좌표/청크, 업스트림 rate limit(1req/s) 고려 1.2s 간격
 */

/** File 의 폴더 내 파일명 (webkitRelativePath 마지막 세그먼트). */
function baseNameOf(f: File): string {
  const p = f.webkitRelativePath || f.name;
  return p.split('/').pop() ?? f.name;
}

function isInBuilding(f: File): boolean {
  const parts = (f.webkitRelativePath || f.name).split('/');
  return parts.length >= 2 && parts[parts.length - 2].toLowerCase() === 'building';
}

/** 표고가 필요한(없거나 0) 좌표 목록 수집. */
function collectMissing(text: string): { key: string; lat: number; lon: number }[] {
  const need: { key: string; lat: number; lon: number }[] = [];
  const seen = new Set<string>();
  for (const block of text.matchAll(/<coordinates>([\s\S]*?)<\/coordinates>/g)) {
    for (const tok of block[1].trim().split(/\s+/)) {
      const p = tok.split(',');
      if (p.length < 2) continue;
      const lon = parseFloat(p[0]), lat = parseFloat(p[1]);
      if (!isFinite(lon) || !isFinite(lat)) continue;
      const alt = p.length >= 3 ? parseFloat(p[2]) : NaN;
      if (isFinite(alt) && alt > 0) continue; // 이미 표고 보유
      const key = `${p[0]},${p[1]}`;
      if (!seen.has(key)) { seen.add(key); need.push({ key, lat, lon }); }
    }
  }
  return need;
}

/**
 * 폴더 파일들에서 표고 없는 KML 을 찾아 `<이름>_byDem.kml` 을 생성·다운로드한다.
 * 생성한 파일명 목록을 반환(생성할 것이 없으면 빈 배열).
 */
export async function generateByDemKmls(input: FileList | File[]): Promise<string[]> {
  const files = Array.from(input);
  const kmls = files.filter((f) => !isInBuilding(f) && /\.kml$/i.test(baseNameOf(f)));
  const lowerNames = new Set(kmls.map((f) => baseNameOf(f).toLowerCase()));
  const made: string[] = [];

  for (const f of kmls) {
    const base = baseNameOf(f).replace(/\.kml$/i, '');
    if (/_bydem$/i.test(base)) continue;                          // 자신이 DEM 버전
    if (lowerNames.has(`${base.toLowerCase()}_bydem.kml`)) continue; // DEM 버전이 이미 폴더에 있음

    const text = await f.text();
    const need = collectMissing(text);
    if (!need.length) continue;                                    // 전 좌표 표고 보유 → 불필요

    // DEM 조회 (서버 프록시)
    const elev = new Map<string, number>();
    for (let i = 0; i < need.length; i += 100) {
      const chunk = need.slice(i, i + 100);
      const r = await fetch(
        `/api/elevation?lat=${chunk.map((c) => c.lat).join(',')}&lon=${chunk.map((c) => c.lon).join(',')}`,
      );
      if (!r.ok) throw new Error(`DEM 조회 실패 (HTTP ${r.status})`);
      const j: { elevation?: (number | null)[] } = await r.json();
      chunk.forEach((c, k) => {
        const e = j.elevation?.[k];
        if (typeof e === 'number' && isFinite(e)) elev.set(c.key, e);
      });
      if (i + 100 < need.length) await new Promise((res) => setTimeout(res, 1200));
    }
    if (!elev.size) continue;

    // 고도 성분 치환(없거나 0 인 것만) — 그 외 텍스트/구조는 원본 그대로 보존
    let next = text.replace(/<coordinates>([\s\S]*?)<\/coordinates>/g, (_m, body: string) =>
      `<coordinates>${body.replace(/(\S+)/g, (tok: string) => {
        const p = tok.split(',');
        if (p.length < 2) return tok;
        const alt = p.length >= 3 ? parseFloat(p[2]) : NaN;
        if (isFinite(alt) && alt > 0) return tok;
        const e = elev.get(`${p[0]},${p[1]}`);
        return e === undefined ? tok : `${p[0]},${p[1]},${e.toFixed(1)}`;
      })}</coordinates>`);

    // '높이' 속성(지장물 스키마)도 0/빈값이면 같은 DEM 표고로 채운다 — Placemark 단위로
    // 자기 좌표의 표고를 대응. 실제 값이 있는 높이는 보존.
    next = next.replace(/<Placemark[^>]*>[\s\S]*?<\/Placemark>/g, (pm) => {
      const cm = pm.match(/<coordinates>\s*([-\d.]+),([-\d.]+)/);
      if (!cm) return pm;
      const e = elev.get(`${cm[1]},${cm[2]}`);
      if (e === undefined) return pm;
      return pm.replace(
        /(<SimpleData name="높이">)\s*(?:0(?:\.0+)?)?\s*(<\/SimpleData>)/,
        `$1${e.toFixed(1)}$2`,
      );
    });

    const outName = `${base}_byDem.kml`;
    const url = URL.createObjectURL(new Blob([next], { type: 'application/vnd.google-earth.kml+xml' }));
    const a = document.createElement('a');
    a.href = url;
    a.download = outName;
    a.click();
    setTimeout(() => URL.revokeObjectURL(url), 5000);
    made.push(outName);
    console.log(`[DEM] ${outName} 생성 — 좌표 ${need.length}개 중 ${elev.size}개 표고 기록`);
  }
  return made;
}
