/**
 * 지리정보 공유 타입 (클라이언트)
 *
 * 서버 server/src/services/geoMatch.ts 의 타입을 그대로 미러링한다.
 * 4개 소비 컴포넌트(GeoSearch / StationVerify / StationOverlay / RoutePanel)와
 * geoStore / geoSearch / geoData 가 공유한다.
 *
 * 주의: DroneFrame 은 utils/geoProjection.ts 의 DroneFrameBasic 와 필드가 동일하다
 * (frame/lat/lon/altitude/yaw/pitch/roll/focalLen). 오버레이 투영 유틸이
 * DroneFrameBasic 을 받으므로, DroneFrame 은 그 타입에 그대로 대입 가능하다.
 */

/** 드론 프레임 (frame별 위경도/자세) — geoMatch.ts DroneFrame 동치 */
export interface DroneFrame {
  frame: number;
  lat: number;
  lon: number;
  altitude: number;
  yaw: number;    // 기수방향 (North=0, 시계방향, degrees)
  pitch: number;  // 카메라 틸트 (음수=아래, degrees)
  roll: number;
  focalLen: number; // 35mm 환산 초점거리 (mm)
}

/** POI/측점 지리점 — geoMatch.ts GeoPoint 동치 */
export interface GeoPoint {
  title: string;
  category: string;
  lat: number;
  lon: number;
  z: number;       // 표고 (m)
  type: 'poi' | 'station';
  /** 원본 CSV 속성(라벨 클릭 팝업에 표시). 순서 보존 위해 배열. */
  props?: { k: string; v: string }[];
  /** 라벨 표시 색(CSS). KML 텍스트박스_색상/IconStyle 유래. 없으면 기본색. */
  labelColor?: string;
}

/** 의미상 별칭 (POI = GeoPoint, Station = GeoPoint with type==='station') */
export type Poi = GeoPoint;
export type Station = GeoPoint;

/** POI 위치 보정값 (마우스 드래그로 생성). title 키로 매칭. z는 정표고(투영이 geoid 가산). */
export interface PoiOverride {
  lat: number;
  lon: number;
  z: number;
}
/** title → 보정좌표. `<base>_poi_overrides.json` 으로 내보내기/가져오기. */
export type PoiOverrideMap = Record<string, PoiOverride>;

/** 선로 중심선 점 — geoMatch.ts CenterlinePoint 동치 */
export interface CenterlinePoint {
  lat: number;
  lon: number;
  z: number;  // 타원체고(h)
}

/** 건물/측점명 검색 결과 프레임 — geoMatch.ts FrameMatch 동치 (+ 그룹 메타) */
export interface FrameMatch {
  frame: number;
  time: number;          // 초 단위 (frame / fps)
  bearingDiff: number;   // 수평 각도차 (degrees)
  elevationDiff: number; // 수직 각도차 (degrees)
  distance: number;      // 수평 거리 (m)
  pixelX: number;        // 0~1 정규화
  pixelY: number;        // 0~1 정규화
  groupSize?: number;    // 연속 구간 프레임 수
  groupStart?: number;   // 구간 시작 프레임
  groupEnd?: number;     // 구간 끝 프레임
}

/** 프레임→POI 역조회 결과 항목 — geoMatch.ts PoiInFrame 동치 */
export interface PoiInFrame {
  poi: GeoPoint;
  bearingDiff: number;
  elevationDiff: number;
  distance: number;
  pixelX: number;
  pixelY: number;
}

/** ENU 월드 원점 (첫 측점 기준) */
export interface GeoOrigin {
  lat: number;
  lon: number;
  alt: number;
}

/** 노선 구조물 (교량/터널) — v2.0 CSV(03)교량/04)터널/06)구교) 유래 + route.json 보정 항목.
 *  구교(category='구교')는 교량 아이콘을 쓰므로 type='bridge' 로 매핑한다. */
export interface RouteStructure {
  id: string;
  /** bridge=교량(구교 포함), tunnel=터널, station(또는 그 외)=역사. */
  type: 'bridge' | 'tunnel' | 'station';
  name: string;
  /** 선택(최우선): 이 측점값에 시설물을 배치. 숫자(미터, 158400) 또는 "158k400" 문자열.
   *  동명 시설물은 각자의 station 값으로 구분 표시된다. */
  station?: number | string;
  /** 선택: 구조물 실좌표. station 없을 때 이 좌표로 배치(POI 매칭 불필요).
   *  v2.0 CSV 구조물은 lat/lon 을 항상 채운다. */
  lat?: number;
  lon?: number;
  /** 선택: 위치는 POI 실좌표(이름 매칭)로 계산. 이정값은 매칭 실패 시 폴백용. */
  startMileage?: number;
  endMileage?: number;
  /** 선택: POI/좌표 기반 위치를 진행방향으로 ±N미터 미세조정. */
  offset?: number;
  /** 선택: 구조물 연장(m). CSV `연장(m)` 컬럼 유래. */
  lengthM?: number;
  /** 선택: 분류 라벨(교량/터널/구교 등). 표시/디버깅용. */
  category?: string;
  /** 선택: 시설종별 원문(예 '1종'|'2종'|'3종'|'기타'). CSV `시설종별` 컬럼 유래.
   *  교량/터널만 채워지고 구교(컬럼 없음)는 undefined. 빈 값도 undefined. */
  grade?: string;
  /** 원본 CSV 속성(라벨 클릭 팝업 표시). */
  props?: { k: string; v: string }[];
}

/** 측점 비고(방향전환점) 파싱 결과 — FolderGeoData.directionChanges.
 *  CSV 01)측점 비고 컬럼의 `방향전환점(상행->하행, 02:05)` 형태에서 추출한다. */
export interface DirectionChange {
  /** 전환이 일어나는 측점값 (예 "157K930"). */
  station: string;
  /** 전환 전 방향 (예 "상행"). */
  from: string;
  /** 전환 후 방향 (예 "하행"). */
  to: string;
  /** 전환 시각(초). mm:ss 표기를 초로 변환 (02:05 → 125). */
  atSeconds: number;
}

/** 노선 기본 정보 — route.json routeInfo */
export interface RouteInfo {
  name?: string;
  direction?: string;
  lengthKm?: number;
  durationSec?: number;
  startStationName?: string;
  endStationName?: string;
  /** 노선 기준 타원체고(m) — 타원체고 기준 데이터셋 참고값(파일에서 통과, 현재 투영엔 미사용). */
  ellipsoidal_height?: number;
  /** 개발 모드: 1(기본)=영상제어 버튼·제어 UI 표시, 0=숨김(뷰어 모드). */
  dev_mode?: number;
  /** 스테이션바 배지 전방 오프셋(m). 미설정/0=드론 연직 체이니지(기본, 기존 동작),
   *  N=진행방향 +N(m) 고정, "auto"=자동(짐벌 피치·AGL 기반 카메라 시선 중심).
   *  활성 시 노선 밖(접근/이탈)에서는 시선 지점을 노선에 투영해 측점값 전환이 앞당겨진다. */
  station_lookahead?: number | string;
  /** 오버레이 자세 필터 저속 컷오프(Hz, 기본 0.8) — 작을수록 직진 시 떨림 억제가 강함. */
  att_min_cut?: number;
  /** 오버레이 자세 필터 속도 계수(기본 0.5) — 클수록 팬(회전) 추종이 민감. */
  att_beta?: number;
  /** 측점 인정 범위(m): station 위치를 이 거리 이내로 지날 때 마커 표시. 기본 40. 폴더별 조절. */
  stationTolerance?: number;
  /**
   * 종점역 '미도착' 거리(m). 영상이 종점역에 도착하지 못하고 이 거리만큼 못 미쳐 끝날 때 설정.
   * 스테이션바는 영상 타임라인을 트랙의 [시작 … 끝−미도착폭]에만 매핑하고,
   * 종점역 마커는 트랙 끝(미도착 스타일)에 둔다. 미설정/0이면 종점역이 끝에 정확히 붙음(도착).
   */
  endStationGapMeters?: number;
}

/** 폴더 보조 파일 <base>.route.json (없으면 route.json) 파싱 결과 */
export interface RouteMeta {
  routeInfo?: RouteInfo;
  structures?: RouteStructure[];
}

/** 영상 파일(djmd 트랙)에서 자동 감지한 드론 카메라 정보 */
export interface DetectedCameraInfo {
  /** 카메라 모델 (예: "DJI ZenmuseP1") */
  model: string;
  /** 35mm 환산 초점거리(mm) — djmd 필드 8.6(0.1mm 단위) 유래 */
  focalLen35?: number;
  width?: number;
  height?: number;
  fps?: number;
  /** 영상 시작 시점 드론 타원체고(m) — djmd 필드 6.6(mm) 유래. 타원체고 기준 데이터셋 변환용. */
  ellipsoidalAltM?: number;
}

/** loadFolderGeoData 파싱 결과 (v2.0 데이터 형상) */
export interface FolderGeoData {
  videoFile: File | null;
  baseName: string | null;
  frames: DroneFrame[];
  /** 전체 비행(모든 세그먼트) 프레임 — 측점 '전 구간' 검색용. 표시용 frames 와 별개. */
  fullFrames: DroneFrame[];
  pois: GeoPoint[];        // type==='poi' (KMZ 원본: 지장물·출입문 등)
  stations: GeoPoint[];    // type==='station' (측점.csv, stationOrder 정렬)
  centerline: CenterlinePoint[]; // 측점을 mileage 순으로 이은 폴리라인 (v2.0엔 center.csv 없음)
  origin: GeoOrigin | null;
  routeMeta: RouteMeta | null;
  /** KMZ 원본 구조물(교량/터널/구교/역사) + route.json 보정. */
  structures: RouteStructure[];
  /** 측점 비고에서 추출한 방향전환점 목록. */
  directionChanges: DirectionChange[];
  /** 폴더의 `<base>_poi_overrides.json` 에서 읽은 POI 위치 보정값 (없으면 {}). */
  poiOverrides: PoiOverrideMap;
  /** KMZ(POI·구조물 원본)가 없거나 비어 있음 → 데이터 누락(재구축 필요). 측점·드론은 별개. */
  kmzMissing: boolean;
  /** 폴더 내 영상 파일 전체(이름 오름차순) — 분할본 연속재생용. videoFile === videoFiles[0]. */
  videoFiles: File[];
  /** videoFiles 와 짝을 이루는 각 영상 길이(초). 메타데이터 측정 실패 시 null. */
  videoDurations: (number | null)[];
  /** 폴더 원본 파일 전체 — 세그먼트 전환 시 드론 CSV 재파싱용. */
  folderFiles: File[];
  /** 영상 djmd 트랙에서 감지한 카메라 정보 (DJI 아닌 영상이면 null). */
  cameraInfo: DetectedCameraInfo | null;
  /** 폴더의 `<영상 base>.camera.json` 카메라 파라미터 (없으면 null). 최우선 적용. */
  cameraJson: Record<string, number> | null;
  /** 폴더의 `<영상 base>.display.json` 화면표시 옵션 (없으면 null). 자동 적용. */
  displayJson: Record<string, unknown> | null;
  /** 드론 고도 datum 보정(m) — 타원체고 기준 데이터셋에서 CSV 정표고→타원체고 변환량(지오이드고).
   *  세그먼트 전환 재파싱 시에도 동일 적용. 정표고 데이터셋은 0. */
  altitudeOffsetM: number;
}
