import { formatAppDecimal } from './numberFormat.js'

/** Barometric pressure (hPa), typical marine range. */
export const PRESSURE_MIN_HPA = 960
export const PRESSURE_MAX_HPA = 1050
export const PRESSURE_DEFAULT_HPA = 1013

/** Douglas sea state 0–9. */
export const SEA_STATE_MIN = 0
export const SEA_STATE_MAX = 9

/** Heel angle in degrees. */
export const HEEL_MIN_DEG = 0
export const HEEL_MAX_DEG = 45

/** Log-spaced visibility steps in metres; index 0 = not set. */
export const VISIBILITY_STEPS_M = [
  0, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000
] as const

function parseDecimal(value: string): number | null {
  const trimmed = value.trim().replace(',', '.')
  if (!trimmed) return null
  const n = Number(trimmed)
  return Number.isFinite(n) ? n : null
}

export function clamp(n: number, min: number, max: number): number {
  return Math.min(max, Math.max(min, n))
}

export function parsePressureHpa(value: string): number | null {
  const raw = value.trim().replace(/\s*hPa\s*$/i, '')
  if (!raw) return null
  const n = parseDecimal(raw)
  if (n == null) return null
  return clamp(Math.round(n), PRESSURE_MIN_HPA, PRESSURE_MAX_HPA)
}

export function formatPressureHpa(hpa: number): string {
  return String(clamp(Math.round(hpa), PRESSURE_MIN_HPA, PRESSURE_MAX_HPA))
}

export function parseSeaState(value: string): number | null {
  const raw = value.trim()
  if (!raw) return null
  const n = parseDecimal(raw)
  if (n == null) return null
  if (!Number.isInteger(n) || n < SEA_STATE_MIN || n > SEA_STATE_MAX) return null
  return n
}

export function formatSeaState(level: number): string {
  return String(clamp(Math.round(level), SEA_STATE_MIN, SEA_STATE_MAX))
}

export function parseHeelDeg(value: string): number | null {
  const raw = value.trim().replace(/°\s*$/, '')
  if (!raw) return null
  const n = parseDecimal(raw)
  if (n == null) return null
  return clamp(Math.round(n), HEEL_MIN_DEG, HEEL_MAX_DEG)
}

export function formatHeelDeg(deg: number): string {
  return String(clamp(Math.round(deg), HEEL_MIN_DEG, HEEL_MAX_DEG))
}

export function parseVisibilityMeters(value: string): number | null {
  const raw = value.trim()
  if (!raw) return null

  const kmMatch = raw.match(/^([\d.,]+)\s*km$/i)
  if (kmMatch) {
    const km = parseDecimal(kmMatch[1])
    return km == null ? null : Math.round(km * 1000)
  }

  const mMatch = raw.match(/^([\d.,]+)\s*m$/i)
  if (mMatch) {
    const m = parseDecimal(mMatch[1])
    return m == null ? null : Math.round(m)
  }

  const bare = parseDecimal(raw)
  if (bare == null) return null
  return Math.round(bare >= 100 ? bare : bare)
}

export function formatVisibilityMeters(meters: number): string {
  if (meters <= 0) return ''
  if (meters >= 1000) {
    const km = meters / 1000
    const rounded = Math.round(km * 10) / 10
    return Number.isInteger(rounded)
      ? `${formatAppDecimal(rounded, { maximumFractionDigits: 0 })} km`
      : `${formatAppDecimal(rounded, { minimumFractionDigits: 1, maximumFractionDigits: 1 })} km`
  }
  return `${Math.round(meters)} m`
}

export function visibilityStepIndex(meters: number): number {
  if (meters <= 0) return 0
  let bestIdx = 1
  let bestDiff = Math.abs(VISIBILITY_STEPS_M[1] - meters)
  for (let i = 2; i < VISIBILITY_STEPS_M.length; i++) {
    const diff = Math.abs(VISIBILITY_STEPS_M[i] - meters)
    if (diff < bestDiff) {
      bestDiff = diff
      bestIdx = i
    }
  }
  return bestIdx
}

export function visibilityMetersFromStepIndex(index: number): number {
  const i = clamp(Math.round(index), 0, VISIBILITY_STEPS_M.length - 1)
  return VISIBILITY_STEPS_M[i]
}

/** Re-export for OWM formatting consistency. */
export { formatOwmVisibilityMeters } from './openWeatherMap.js'
