/**
 * Leitungsrechner — Druckverlust-Berechnung für Schlauchleitungen (Schweizer Standard).
 *
 * EINZIGE Quelle für die Formel. Wird vom Messwerkzeug (MeasurePanel) und vom
 * HoseSettingsDialog verwendet — keine duplizierten Berechnungen mehr.
 *
 * Faustformel Reibungsverlust: R = c · (Q/100)² · (L/100)
 *   c = Reibungskoeffizient des Schlauchtyps [bar/100m bei 100 l/min]
 *   Q = Durchfluss [l/min], L = Leitungslänge [m]
 */

export interface HoseTypeData {
  id?: string
  name: string
  diameterMm: number
  flowRateLpm: number
  frictionCoeff: number
  lengthPerPieceM: number
  isDefault?: boolean
}

export interface CalcParams {
  /** Erforderlicher Druck am Strahlrohr/Verteiler [bar] */
  nozzlePressure: number
  /** Maximaler Förderdruck einer Pumpe (TS/FP) [bar] */
  pumpMaxPressure: number
  /** Druckänderung pro Meter Höhendifferenz [bar/m] */
  elevationFactor: number
  /** Verlegefaktor: reale Schlauchstrecke vs. Luftlinie (z.B. 1.1 = +10% Reserve) */
  layoutFactor: number
}

/** Schweizer Standardwerte */
export const DEFAULT_CALC_PARAMS: CalcParams = {
  nozzlePressure: 5.0,
  pumpMaxPressure: 10.0,
  elevationFactor: 0.1,
  layoutFactor: 1.1,
}

/** Fallback-Schlauchtypen, falls die API keine liefert (Schweizer Standard). */
export const FALLBACK_HOSE_TYPES: HoseTypeData[] = [
  { name: '55mm Transportleitung', diameterMm: 55, flowRateLpm: 500, frictionCoeff: 0.034, lengthPerPieceM: 20, isDefault: true },
  { name: '75mm Zubringerleitung', diameterMm: 75, flowRateLpm: 1500, frictionCoeff: 0.012, lengthPerPieceM: 20 },
]

/** Reibungsverlust pro 100 m für einen Schlauchtyp [bar/100m]. */
export function frictionPer100m(hose: Pick<HoseTypeData, 'frictionCoeff' | 'flowRateLpm'>): number {
  return hose.frictionCoeff * Math.pow(hose.flowRateLpm / 100, 2)
}

export interface HoseCalcResult {
  hose: HoseTypeData
  /** Effektive Leitungslänge inkl. Verlegefaktor [m] */
  effectiveLengthM: number
  /** Reibungsverlust über die ganze Leitung [bar] */
  frictionBar: number
  /** Reibungsverlust pro 100 m [bar] */
  frictionPer100mBar: number
  /** Druck aus Höhendifferenz [bar] (positiv = bergauf) */
  elevationBar: number
  /** Benötigter Pumpen-Ausgangsdruck gesamt [bar] */
  totalBar: number
  /** Anzahl benötigter Pumpen (inkl. erster) */
  pumpCount: number
  /** Abstand zwischen Verstärkerpumpen [m], null wenn 1 Pumpe reicht */
  boosterSpacingM: number | null
  /** Anzahl Schläuche (effektive Länge / Länge pro Stück, aufgerundet) */
  hoseCount: number
  /** true wenn der Gesamtdruck den max. Pumpendruck übersteigt */
  needsBooster: boolean
}

/**
 * Berechnet Druckbedarf & Materialbedarf für EINE Leitung.
 * @param distanceM   Gemessene Distanz (Luftlinie entlang der Messpunkte) [m]
 * @param netElevationDiffM  Netto-Höhendifferenz Ende − Start [m] (positiv = bergauf)
 */
export function calcHoseLine(
  distanceM: number,
  netElevationDiffM: number,
  hose: HoseTypeData,
  params: CalcParams = DEFAULT_CALC_PARAMS
): HoseCalcResult {
  const effectiveLengthM = distanceM * params.layoutFactor
  const per100 = frictionPer100m(hose)
  const frictionBar = per100 * (effectiveLengthM / 100)
  const elevationBar = netElevationDiffM * params.elevationFactor
  const totalBar = frictionBar + elevationBar + params.nozzlePressure
  const pumpCount = Math.max(1, Math.ceil(Math.max(totalBar, 0) / params.pumpMaxPressure))
  const hoseCount = hose.lengthPerPieceM > 0 ? Math.ceil(effectiveLengthM / hose.lengthPerPieceM) : 0

  return {
    hose,
    effectiveLengthM,
    frictionBar,
    frictionPer100mBar: per100,
    elevationBar,
    totalBar,
    pumpCount,
    boosterSpacingM: pumpCount > 1 ? distanceM / (pumpCount - 1) : null,
    hoseCount,
    needsBooster: pumpCount > 1,
  }
}

/** Zusammenfassung einer Streckenmessung (Distanz + Höhenprofil). */
export interface MeasurementSummary {
  totalDistanceM: number
  elevationStartM: number
  elevationEndM: number
  netDiffM: number
  climbM: number
  descentM: number
  minElevationM: number
  maxElevationM: number
  samplePointCount: number
  /** Woher die Höhendaten stammen — 'none' = nicht verfügbar (flach gerechnet) */
  elevationSource: 'open-meteo' | 'open-elevation' | 'none'
}
