//! CO₂ / supercritical gas cooler HTC (Pettersen / Cheng–Thome simplified).
//!
//! Activated when `P > P_crit`. Uses a Gnielinski-like single-phase form with a
//! specific-heat peak correction near the pseudo-critical temperature.

use super::bphx_correlation::{BphxCorrelation, CorrelationParams, FlowRegime};

/// Inputs for gas-cooler HTC evaluation.
#[derive(Debug, Clone, Copy)]
pub struct GasCoolerInput {
    /// Pressure [Pa].
    pub pressure_pa: f64,
    /// Critical pressure [Pa].
    pub p_crit_pa: f64,
    /// Bulk temperature [K].
    pub t_bulk_k: f64,
    /// Pseudo-critical temperature at this pressure [K] (≈ 304–320 K for CO₂).
    pub t_pc_k: f64,
    /// Mass flux [kg/(m²·s)].
    pub mass_flux: f64,
    /// Hydraulic diameter [m].
    pub dh: f64,
    /// Density [kg/m³].
    pub rho: f64,
    /// Dynamic viscosity [Pa·s].
    pub mu: f64,
    /// Thermal conductivity [W/(m·K)].
    pub k: f64,
    /// Prandtl number [-].
    pub pr: f64,
}

/// Returns true when the stream is supercritical (gas-cooler regime).
pub fn is_supercritical(pressure_pa: f64, p_crit_pa: f64) -> bool {
    pressure_pa > p_crit_pa && p_crit_pa > 0.0
}

/// Pettersen-style HTC with pseudo-critical enhancement [W/(m²·K)].
///
/// Base: Gnielinski single-phase. Near `T_pc`, multiply by
/// `1 + 0.8 · exp(−((T−T_pc)/15)²)` to capture the c_p peak.
pub fn pettersen_htc(input: &GasCoolerInput) -> f64 {
    let params = CorrelationParams {
        mass_flux: input.mass_flux,
        quality: 0.0,
        dh: input.dh,
        rho_l: input.rho,
        rho_v: input.rho,
        mu_l: input.mu,
        mu_v: input.mu,
        k_l: input.k,
        pr_l: input.pr,
        t_sat: input.t_bulk_k,
        t_wall: input.t_bulk_k + 5.0,
        regime: FlowRegime::SinglePhaseVapor,
        chevron_angle: 60.0,
        p_reduced: (input.pressure_pa / input.p_crit_pa.max(1.0)).min(0.99),
    };
    let base = BphxCorrelation::Gnielinski1976.compute_htc(&params).h;
    let d_t = (input.t_bulk_k - input.t_pc_k) / 15.0;
    let enhance = 1.0 + 0.8 * (-d_t * d_t).exp();
    (base * enhance).max(50.0)
}

/// Gas cooler component wrapper: stores UA from Pettersen HTC × area.
#[derive(Debug, Clone)]
pub struct GasCooler {
    /// Heat-transfer area [m²].
    area_m2: f64,
    /// Last HTC [W/(m²·K)].
    last_htc: f64,
    /// Last UA [W/K].
    last_ua: f64,
}

impl GasCooler {
    /// Creates a gas cooler with given heat-transfer area.
    pub fn new(area_m2: f64) -> Self {
        Self {
            area_m2: area_m2.max(1e-6),
            last_htc: 0.0,
            last_ua: 0.0,
        }
    }

    /// Updates HTC/UA from operating point.
    pub fn update(&mut self, input: &GasCoolerInput) -> f64 {
        self.last_htc = pettersen_htc(input);
        self.last_ua = self.last_htc * self.area_m2;
        self.last_ua
    }

    /// Last UA [W/K].
    pub fn ua(&self) -> f64 {
        self.last_ua
    }

    /// Last HTC [W/(m²·K)].
    pub fn htc(&self) -> f64 {
        self.last_htc
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn co2_input(t_k: f64) -> GasCoolerInput {
        GasCoolerInput {
            pressure_pa: 90e5,
            p_crit_pa: 73.77e5,
            t_bulk_k: t_k,
            t_pc_k: 310.0,
            mass_flux: 400.0,
            dh: 0.001,
            rho: 400.0,
            mu: 3e-5,
            k: 0.05,
            pr: 2.0,
        }
    }

    #[test]
    fn supercritical_detected() {
        assert!(is_supercritical(90e5, 73.77e5));
        assert!(!is_supercritical(50e5, 73.77e5));
    }

    #[test]
    fn htc_peaks_near_tpc() {
        let h_peak = pettersen_htc(&co2_input(310.0));
        let h_far = pettersen_htc(&co2_input(340.0));
        assert!(h_peak > h_far);
    }

    #[test]
    fn update_sets_ua() {
        let mut gc = GasCooler::new(2.0);
        let ua = gc.update(&co2_input(315.0));
        assert!(ua > 0.0 && (ua - gc.htc() * 2.0).abs() < 1e-6);
    }
}
