import { wingPool } from '../db/wingDb.js';

// ============================================================
// 인터페이스
// ============================================================

interface IncidentListItem {
  acdntSn: number;
  acdntCd: string;
  acdntNm: string;
  acdntTpCd: string;
  acdntSttsCd: string;
  lat: number;
  lng: number;
  locDc: string;
  occrnDtm: string;
  regionNm: string;
  officeNm: string;
  svrtCd: string | null;
  vesselTp: string | null;
  phaseCd: string;
  analystNm: string | null;
  oilTpCd: string | null;
  spilQty: number | null;
  spilUnitCd: string | null;
  fcstHr: number | null;
  mediaCnt: number;
}

interface PredExecItem {
  predExecSn: number;
  algoCd: string;
  execSttsCd: string;
  bgngDtm: string | null;
  cmplDtm: string | null;
  reqdSec: number | null;
}

interface WeatherInfo {
  locNm: string;
  obsDtm: string;
  icon: string;
  temp: string;
  weatherDc: string;
  wind: string;
  wave: string;
  humid: string;
  vis: string;
  sst: string;
  tide: string;
  highTide: string;
  lowTide: string;
  forecast: Array<{ hour: string; icon: string; temp: string }>;
  impactDc: string;
}

interface MediaInfo {
  photoCnt: number;
  videoCnt: number;
  satCnt: number;
  cctvCnt: number;
  photoMeta: Record<string, unknown> | null;
  droneMeta: Record<string, unknown> | null;
  satMeta: Record<string, unknown> | null;
  cctvMeta: Record<string, unknown> | null;
}

interface IncidentDetail extends IncidentListItem {
  predictions: PredExecItem[];
  weather: WeatherInfo | null;
  media: MediaInfo | null;
}

// ============================================================
// 사고 목록 조회
// ============================================================
export async function listIncidents(filters: {
  status?: string;
  region?: string;
  search?: string;
  startDate?: string;
  endDate?: string;
}): Promise<IncidentListItem[]> {
  const conditions: string[] = ["a.USE_YN = 'Y'"];
  const params: unknown[] = [];
  let idx = 1;

  if (filters.status) {
    conditions.push(`a.ACDNT_STTS_CD = $${idx++}`);
    params.push(filters.status);
  }
  if (filters.region) {
    conditions.push(`a.REGION_NM LIKE '%' || $${idx++} || '%'`);
    params.push(filters.region);
  }
  if (filters.search) {
    conditions.push(`a.ACDNT_NM LIKE '%' || $${idx++} || '%'`);
    params.push(filters.search);
  }
  if (filters.startDate) {
    conditions.push(`a.OCCRN_DTM >= $${idx++}`);
    params.push(filters.startDate);
  }
  if (filters.endDate) {
    conditions.push(`a.OCCRN_DTM <= $${idx++}`);
    params.push(filters.endDate);
  }

  const sql = `
    SELECT a.ACDNT_SN, a.ACDNT_CD, a.ACDNT_NM, a.ACDNT_TP_CD, a.ACDNT_STTS_CD,
           a.LAT, a.LNG, a.LOC_DC, a.OCCRN_DTM, a.REGION_NM, a.OFFICE_NM,
           a.SVRT_CD, a.VESSEL_TP, a.PHASE_CD, a.ANALYST_NM,
           s.OIL_TP_CD, s.SPIL_QTY, s.SPIL_UNIT_CD, s.FCST_HR,
           COALESCE(m.PHOTO_CNT, 0) + COALESCE(m.VIDEO_CNT, 0)
             + COALESCE(m.SAT_CNT, 0) + COALESCE(m.CCTV_CNT, 0) AS media_cnt
    FROM wing.ACDNT a
    LEFT JOIN LATERAL (
      SELECT OIL_TP_CD, SPIL_QTY, SPIL_UNIT_CD, FCST_HR
      FROM wing.SPIL_DATA
      WHERE ACDNT_SN = a.ACDNT_SN
      ORDER BY SPIL_DATA_SN
      LIMIT 1
    ) s ON TRUE
    LEFT JOIN wing.ACDNT_MEDIA m ON m.ACDNT_SN = a.ACDNT_SN
    WHERE ${conditions.join(' AND ')}
    ORDER BY a.OCCRN_DTM DESC
  `;

  const { rows } = await wingPool.query(sql, params);

  return rows.map((r: Record<string, unknown>) => ({
    acdntSn: r.acdnt_sn as number,
    acdntCd: r.acdnt_cd as string,
    acdntNm: r.acdnt_nm as string,
    acdntTpCd: r.acdnt_tp_cd as string,
    acdntSttsCd: r.acdnt_stts_cd as string,
    lat: parseFloat(r.lat as string),
    lng: parseFloat(r.lng as string),
    locDc: r.loc_dc as string,
    occrnDtm: (r.occrn_dtm as Date).toISOString(),
    regionNm: r.region_nm as string,
    officeNm: r.office_nm as string,
    svrtCd: (r.svrt_cd as string) ?? null,
    vesselTp: (r.vessel_tp as string) ?? null,
    phaseCd: r.phase_cd as string,
    analystNm: (r.analyst_nm as string) ?? null,
    oilTpCd: (r.oil_tp_cd as string) ?? null,
    spilQty: r.spil_qty != null ? parseFloat(r.spil_qty as string) : null,
    spilUnitCd: (r.spil_unit_cd as string) ?? null,
    fcstHr: (r.fcst_hr as number) ?? null,
    mediaCnt: Number(r.media_cnt),
  }));
}

// ============================================================
// 사고 상세 조회
// ============================================================
export async function getIncident(acdntSn: number): Promise<IncidentDetail | null> {
  // 기본 정보 + 첫 유출건
  const baseSql = `
    SELECT a.ACDNT_SN, a.ACDNT_CD, a.ACDNT_NM, a.ACDNT_TP_CD, a.ACDNT_STTS_CD,
           a.LAT, a.LNG, a.LOC_DC, a.OCCRN_DTM, a.REGION_NM, a.OFFICE_NM,
           a.SVRT_CD, a.VESSEL_TP, a.PHASE_CD, a.ANALYST_NM,
           s.OIL_TP_CD, s.SPIL_QTY, s.SPIL_UNIT_CD, s.FCST_HR,
           COALESCE(m.PHOTO_CNT, 0) + COALESCE(m.VIDEO_CNT, 0)
             + COALESCE(m.SAT_CNT, 0) + COALESCE(m.CCTV_CNT, 0) AS media_cnt
    FROM wing.ACDNT a
    LEFT JOIN LATERAL (
      SELECT OIL_TP_CD, SPIL_QTY, SPIL_UNIT_CD, FCST_HR
      FROM wing.SPIL_DATA
      WHERE ACDNT_SN = a.ACDNT_SN
      ORDER BY SPIL_DATA_SN
      LIMIT 1
    ) s ON TRUE
    LEFT JOIN wing.ACDNT_MEDIA m ON m.ACDNT_SN = a.ACDNT_SN
    WHERE a.ACDNT_SN = $1 AND a.USE_YN = 'Y'
  `;

  const { rows: baseRows } = await wingPool.query(baseSql, [acdntSn]);
  if (baseRows.length === 0) return null;

  const r = baseRows[0] as Record<string, unknown>;

  const predictions = await listIncidentPredictions(acdntSn);
  const weather = await getIncidentWeather(acdntSn);
  const media = await getIncidentMedia(acdntSn);

  return {
    acdntSn: r.acdnt_sn as number,
    acdntCd: r.acdnt_cd as string,
    acdntNm: r.acdnt_nm as string,
    acdntTpCd: r.acdnt_tp_cd as string,
    acdntSttsCd: r.acdnt_stts_cd as string,
    lat: parseFloat(r.lat as string),
    lng: parseFloat(r.lng as string),
    locDc: r.loc_dc as string,
    occrnDtm: (r.occrn_dtm as Date).toISOString(),
    regionNm: r.region_nm as string,
    officeNm: r.office_nm as string,
    svrtCd: (r.svrt_cd as string) ?? null,
    vesselTp: (r.vessel_tp as string) ?? null,
    phaseCd: r.phase_cd as string,
    analystNm: (r.analyst_nm as string) ?? null,
    oilTpCd: (r.oil_tp_cd as string) ?? null,
    spilQty: r.spil_qty != null ? parseFloat(r.spil_qty as string) : null,
    spilUnitCd: (r.spil_unit_cd as string) ?? null,
    fcstHr: (r.fcst_hr as number) ?? null,
    mediaCnt: Number(r.media_cnt),
    predictions,
    weather,
    media,
  };
}

// ============================================================
// 예측 실행 목록 조회
// ============================================================
export async function listIncidentPredictions(acdntSn: number): Promise<PredExecItem[]> {
  const sql = `
    SELECT PRED_EXEC_SN, ALGO_CD, EXEC_STTS_CD, BGNG_DTM, CMPL_DTM, REQD_SEC
    FROM wing.PRED_EXEC
    WHERE ACDNT_SN = $1
    ORDER BY ALGO_CD
  `;

  const { rows } = await wingPool.query(sql, [acdntSn]);

  return rows.map((r: Record<string, unknown>) => ({
    predExecSn: r.pred_exec_sn as number,
    algoCd: r.algo_cd as string,
    execSttsCd: r.exec_stts_cd as string,
    bgngDtm: r.bgng_dtm ? (r.bgng_dtm as Date).toISOString() : null,
    cmplDtm: r.cmpl_dtm ? (r.cmpl_dtm as Date).toISOString() : null,
    reqdSec: (r.reqd_sec as number) ?? null,
  }));
}

// ============================================================
// 기상정보 조회 (최신 1건)
// ============================================================
export async function getIncidentWeather(acdntSn: number): Promise<WeatherInfo | null> {
  const sql = `
    SELECT LOC_NM, OBS_DTM, ICON, TEMP, WEATHER_DC, WIND, WAVE,
           HUMID, VIS, SST, TIDE, HIGH_TIDE, LOW_TIDE, FORECAST, IMPACT_DC
    FROM wing.ACDNT_WEATHER
    WHERE ACDNT_SN = $1
    ORDER BY OBS_DTM DESC
    LIMIT 1
  `;

  const { rows } = await wingPool.query(sql, [acdntSn]);
  if (rows.length === 0) return null;

  const r = rows[0] as Record<string, unknown>;

  return {
    locNm: r.loc_nm as string,
    obsDtm: (r.obs_dtm as Date).toISOString(),
    icon: r.icon as string,
    temp: r.temp as string,
    weatherDc: r.weather_dc as string,
    wind: r.wind as string,
    wave: r.wave as string,
    humid: r.humid as string,
    vis: r.vis as string,
    sst: r.sst as string,
    tide: r.tide as string,
    highTide: r.high_tide as string,
    lowTide: r.low_tide as string,
    forecast: (r.forecast as Array<{ hour: string; icon: string; temp: string }>) ?? [],
    impactDc: r.impact_dc as string,
  };
}

// ============================================================
// 미디어 정보 조회
// ============================================================
export async function getIncidentMedia(acdntSn: number): Promise<MediaInfo | null> {
  const sql = `
    SELECT PHOTO_CNT, VIDEO_CNT, SAT_CNT, CCTV_CNT,
           PHOTO_META, DRONE_META, SAT_META, CCTV_META
    FROM wing.ACDNT_MEDIA
    WHERE ACDNT_SN = $1
    LIMIT 1
  `;

  const { rows } = await wingPool.query(sql, [acdntSn]);
  if (rows.length === 0) return null;

  const r = rows[0] as Record<string, unknown>;

  return {
    photoCnt: (r.photo_cnt as number) ?? 0,
    videoCnt: (r.video_cnt as number) ?? 0,
    satCnt: (r.sat_cnt as number) ?? 0,
    cctvCnt: (r.cctv_cnt as number) ?? 0,
    photoMeta: (r.photo_meta as Record<string, unknown>) ?? null,
    droneMeta: (r.drone_meta as Record<string, unknown>) ?? null,
    satMeta: (r.sat_meta as Record<string, unknown>) ?? null,
    cctvMeta: (r.cctv_meta as Record<string, unknown>) ?? null,
  };
}
