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

interface HnsSearchParams {
  q?: string
  type?: 'abbreviation' | 'nameKr' | 'nameEn' | 'casNumber' | 'unNumber' | 'cargoCode'
  sebc?: string
  page?: number
  limit?: number
}

export async function searchSubstances(params: HnsSearchParams) {
  const { q, type, sebc, page = 1, limit = 50 } = params
  const conditions: string[] = ["USE_YN = 'Y'"]
  const values: (string | number)[] = []
  let paramIdx = 1

  if (q && q.trim()) {
    const keyword = q.trim()
    switch (type) {
      case 'abbreviation':
        conditions.push(`ABBREVIATION ILIKE $${paramIdx}`)
        values.push(`%${keyword}%`)
        break
      case 'nameKr':
        conditions.push(`NM_KR ILIKE $${paramIdx}`)
        values.push(`%${keyword}%`)
        break
      case 'nameEn':
        conditions.push(`NM_EN ILIKE $${paramIdx}`)
        values.push(`%${keyword}%`)
        break
      case 'casNumber':
        conditions.push(`CAS_NO ILIKE $${paramIdx}`)
        values.push(`%${keyword}%`)
        break
      case 'unNumber':
        conditions.push(`UN_NO = $${paramIdx}`)
        values.push(keyword)
        break
      case 'cargoCode':
        conditions.push(`DATA->'cargoCodes' @> $${paramIdx}::jsonb`)
        values.push(JSON.stringify([{ code: keyword }]))
        break
      default:
        conditions.push(`(ABBREVIATION ILIKE $${paramIdx} OR NM_KR ILIKE $${paramIdx} OR NM_EN ILIKE $${paramIdx})`)
        values.push(`%${keyword}%`)
    }
    paramIdx++
  }

  if (sebc && sebc.trim()) {
    conditions.push(`SEBC ILIKE $${paramIdx}`)
    values.push(`%${sebc.trim()}%`)
    paramIdx++
  }

  const where = conditions.join(' AND ')
  const offset = (page - 1) * limit

  const countQuery = `SELECT COUNT(*) as total FROM HNS_SUBSTANCE WHERE ${where}`
  const dataQuery = `
    SELECT SBST_SN, ABBREVIATION, NM_KR, NM_EN, UN_NO, CAS_NO, SEBC, DATA
    FROM HNS_SUBSTANCE
    WHERE ${where}
    ORDER BY SBST_SN
    LIMIT $${paramIdx} OFFSET $${paramIdx + 1}
  `

  const [countResult, dataResult] = await Promise.all([
    wingPool.query(countQuery, values),
    wingPool.query(dataQuery, [...values, limit, offset]),
  ])

  return {
    total: parseInt(countResult.rows[0].total, 10),
    page,
    limit,
    items: dataResult.rows.map(row => ({
      id: row.sbst_sn,
      abbreviation: row.abbreviation,
      nameKr: row.nm_kr,
      nameEn: row.nm_en,
      unNumber: row.un_no,
      casNumber: row.cas_no,
      sebc: row.sebc,
      ...row.data,
    })),
  }
}

// ============================================================
// HNS 분석 CRUD
// ============================================================

interface HnsAnalysisItem {
  hnsAnlysSn: number
  anlysNm: string
  acdntDtm: string | null
  locNm: string | null
  lon: number | null
  lat: number | null
  sbstNm: string | null
  spilQty: number | null
  spilUnitCd: string | null
  fcstHr: number | null
  algoCd: string | null
  critMdlCd: string | null
  windSpd: number | null
  windDir: string | null
  execSttsCd: string
  riskCd: string | null
  analystNm: string | null
  rsltData: Record<string, unknown> | null
  regDtm: string
}

interface ListAnalysesInput {
  status?: string
  substance?: string
  search?: string
}

function rowToAnalysis(r: Record<string, unknown>): HnsAnalysisItem {
  return {
    hnsAnlysSn: r.hns_anlys_sn as number,
    anlysNm: r.anlys_nm as string,
    acdntDtm: r.acdnt_dtm as string | null,
    locNm: r.loc_nm as string | null,
    lon: r.lon ? parseFloat(r.lon as string) : null,
    lat: r.lat ? parseFloat(r.lat as string) : null,
    sbstNm: r.sbst_nm as string | null,
    spilQty: r.spil_qty ? parseFloat(r.spil_qty as string) : null,
    spilUnitCd: r.spil_unit_cd as string | null,
    fcstHr: r.fcst_hr as number | null,
    algoCd: r.algo_cd as string | null,
    critMdlCd: r.crit_mdl_cd as string | null,
    windSpd: r.wind_spd ? parseFloat(r.wind_spd as string) : null,
    windDir: r.wind_dir as string | null,
    execSttsCd: r.exec_stts_cd as string,
    riskCd: r.risk_cd as string | null,
    analystNm: r.analyst_nm as string | null,
    rsltData: (r.rslt_data as Record<string, unknown>) ?? null,
    regDtm: r.reg_dtm as string,
  }
}

export async function listAnalyses(input: ListAnalysesInput): Promise<HnsAnalysisItem[]> {
  const conditions: string[] = ["USE_YN = 'Y'"]
  const params: string[] = []
  let idx = 1

  if (input.status) {
    conditions.push(`EXEC_STTS_CD = $${idx++}`)
    params.push(input.status)
  }
  if (input.substance) {
    conditions.push(`SBST_NM ILIKE '%' || $${idx++} || '%'`)
    params.push(input.substance)
  }
  if (input.search) {
    conditions.push(`(ANLYS_NM ILIKE '%' || $${idx} || '%' OR LOC_NM ILIKE '%' || $${idx} || '%')`)
    params.push(input.search)
    idx++
  }

  const { rows } = await wingPool.query(
    `SELECT HNS_ANLYS_SN, ANLYS_NM, ACDNT_DTM, LOC_NM, LON, LAT,
            SBST_NM, SPIL_QTY, SPIL_UNIT_CD, FCST_HR, ALGO_CD, CRIT_MDL_CD,
            WIND_SPD, WIND_DIR, EXEC_STTS_CD, RISK_CD, ANALYST_NM,
            RSLT_DATA, REG_DTM
     FROM HNS_ANALYSIS
     WHERE ${conditions.join(' AND ')}
     ORDER BY ACDNT_DTM DESC NULLS LAST`,
    params
  )

  return rows.map((r: Record<string, unknown>) => rowToAnalysis(r))
}

export async function getAnalysis(sn: number): Promise<HnsAnalysisItem | null> {
  const { rows } = await wingPool.query(
    `SELECT HNS_ANLYS_SN, ANLYS_NM, ACDNT_DTM, LOC_NM, LON, LAT,
            SBST_NM, SPIL_QTY, SPIL_UNIT_CD, FCST_HR, ALGO_CD, CRIT_MDL_CD,
            WIND_SPD, WIND_DIR, TEMP, HUMID, ATM_STBL_CD,
            EXEC_STTS_CD, RISK_CD, ANALYST_NM,
            RSLT_DATA, REG_DTM
     FROM HNS_ANALYSIS
     WHERE HNS_ANLYS_SN = $1 AND USE_YN = 'Y'`,
    [sn]
  )
  if (rows.length === 0) return null
  return rowToAnalysis(rows[0] as Record<string, unknown>)
}

export async function createAnalysis(input: {
  anlysNm: string
  acdntDtm?: string
  locNm?: string
  lon?: number
  lat?: number
  sbstNm?: string
  spilQty?: number
  spilUnitCd?: string
  fcstHr?: number
  algoCd?: string
  critMdlCd?: string
  windSpd?: number
  windDir?: string
  temp?: number
  humid?: number
  atmStblCd?: string
  analystNm?: string
}): Promise<{ hnsAnlysSn: number }> {
  const { rows } = await wingPool.query(
    `INSERT INTO HNS_ANALYSIS (
      ANLYS_NM, ACDNT_DTM, LOC_NM, LON, LAT,
      GEOM, LOC_DC,
      SBST_NM, SPIL_QTY, SPIL_UNIT_CD, FCST_HR, ALGO_CD, CRIT_MDL_CD,
      WIND_SPD, WIND_DIR, TEMP, HUMID, ATM_STBL_CD,
      ANALYST_NM, EXEC_STTS_CD
    ) VALUES (
      $1, $2, $3, $4::numeric, $5::numeric,
      CASE WHEN $4 IS NOT NULL AND $5 IS NOT NULL THEN ST_SetSRID(ST_MakePoint($4::double precision, $5::double precision), 4326) END,
      CASE WHEN $4 IS NOT NULL AND $5 IS NOT NULL THEN $4::text || ' + ' || $5::text END,
      $6, $7, $8, $9, $10, $11,
      $12, $13, $14, $15, $16,
      $17, 'PENDING'
    ) RETURNING HNS_ANLYS_SN`,
    [
      input.anlysNm, input.acdntDtm || null, input.locNm || null, input.lon || null, input.lat || null,
      input.sbstNm || null, input.spilQty || null, input.spilUnitCd || 'KL',
      input.fcstHr || null, input.algoCd || null, input.critMdlCd || null,
      input.windSpd || null, input.windDir || null, input.temp || null, input.humid || null, input.atmStblCd || null,
      input.analystNm || null,
    ]
  )

  return { hnsAnlysSn: rows[0].hns_anlys_sn }
}

export async function updateAnalysisResult(sn: number, input: {
  rsltData: Record<string, unknown>
  execSttsCd?: string
  riskCd?: string
}): Promise<void> {
  await wingPool.query(
    `UPDATE HNS_ANALYSIS
     SET RSLT_DATA = $1, EXEC_STTS_CD = $2, RISK_CD = $3, MDFCN_DTM = NOW()
     WHERE HNS_ANLYS_SN = $4 AND USE_YN = 'Y'`,
    [JSON.stringify(input.rsltData), input.execSttsCd || 'COMPLETED', input.riskCd || null, sn]
  )
}

export async function deleteAnalysis(sn: number): Promise<void> {
  await wingPool.query(
    `UPDATE HNS_ANALYSIS SET USE_YN = 'N', MDFCN_DTM = NOW() WHERE HNS_ANLYS_SN = $1`,
    [sn]
  )
}

export async function getSubstanceById(id: number) {
  const { rows } = await wingPool.query(
    `SELECT SBST_SN, ABBREVIATION, NM_KR, NM_EN, UN_NO, CAS_NO, SEBC, DATA
     FROM HNS_SUBSTANCE WHERE SBST_SN = $1`,
    [id]
  )
  if (rows.length === 0) return null

  const row = rows[0]
  return {
    id: row.sbst_sn,
    abbreviation: row.abbreviation,
    nameKr: row.nm_kr,
    nameEn: row.nm_en,
    unNumber: row.un_no,
    casNumber: row.cas_no,
    sebc: row.sebc,
    ...row.data,
  }
}
