//! WASM type wrappers for core physical types.
//!
//! Provides JavaScript-friendly wrappers for Pressure, Temperature,
//! Enthalpy, and MassFlow with JSON serialization support.

use entropyk_core::{Enthalpy, MassFlow, Pressure, Temperature};
use wasm_bindgen::prelude::*;

/// Pressure in Pascals.
#[wasm_bindgen]
#[derive(Clone, Copy, Debug)]
pub struct WasmPressure {
    pascals: f64,
}

#[wasm_bindgen]
impl WasmPressure {
    /// Create pressure from Pascals.
    #[wasm_bindgen(constructor)]
    pub fn new(pascals: f64) -> Self {
        WasmPressure { pascals }
    }

    /// Create pressure from bar.
    pub fn from_bar(bar: f64) -> Self {
        WasmPressure {
            pascals: bar * 100_000.0,
        }
    }

    /// Get pressure in Pascals.
    pub fn pascals(&self) -> f64 {
        self.pascals
    }

    /// Get pressure in bar.
    pub fn bar(&self) -> f64 {
        self.pascals / 100_000.0
    }

    /// Convert to JSON string.
    pub fn toJson(&self) -> String {
        format!(r#"{{"pascals":{},"bar":{}}}"#, self.pascals, self.bar())
    }
}

impl From<Pressure> for WasmPressure {
    fn from(p: Pressure) -> Self {
        WasmPressure {
            pascals: p.to_pascals(),
        }
    }
}

impl From<WasmPressure> for Pressure {
    fn from(p: WasmPressure) -> Self {
        Pressure::from_pascals(p.pascals)
    }
}

/// Temperature in Kelvin.
#[wasm_bindgen]
#[derive(Clone, Copy, Debug)]
pub struct WasmTemperature {
    kelvin: f64,
}

#[wasm_bindgen]
impl WasmTemperature {
    /// Create temperature from Kelvin.
    #[wasm_bindgen(constructor)]
    pub fn new(kelvin: f64) -> Self {
        WasmTemperature { kelvin }
    }

    /// Create temperature from Celsius.
    pub fn from_celsius(celsius: f64) -> Self {
        WasmTemperature {
            kelvin: celsius + 273.15,
        }
    }

    /// Get temperature in Kelvin.
    pub fn kelvin(&self) -> f64 {
        self.kelvin
    }

    /// Get temperature in Celsius.
    pub fn celsius(&self) -> f64 {
        self.kelvin - 273.15
    }

    /// Convert to JSON string.
    pub fn toJson(&self) -> String {
        format!(
            r#"{{"kelvin":{},"celsius":{}}}"#,
            self.kelvin,
            self.celsius()
        )
    }
}

impl From<Temperature> for WasmTemperature {
    fn from(t: Temperature) -> Self {
        WasmTemperature {
            kelvin: t.to_kelvin(),
        }
    }
}

impl From<WasmTemperature> for Temperature {
    fn from(t: WasmTemperature) -> Self {
        Temperature::from_kelvin(t.kelvin)
    }
}

/// Enthalpy in J/kg.
#[wasm_bindgen]
#[derive(Clone, Copy, Debug)]
pub struct WasmEnthalpy {
    joules_per_kg: f64,
}

#[wasm_bindgen]
impl WasmEnthalpy {
    /// Create enthalpy from J/kg.
    #[wasm_bindgen(constructor)]
    pub fn new(joules_per_kg: f64) -> Self {
        WasmEnthalpy { joules_per_kg }
    }

    /// Create enthalpy from kJ/kg.
    pub fn from_kj_per_kg(kj_per_kg: f64) -> Self {
        WasmEnthalpy {
            joules_per_kg: kj_per_kg * 1000.0,
        }
    }

    /// Get enthalpy in J/kg.
    pub fn joules_per_kg(&self) -> f64 {
        self.joules_per_kg
    }

    /// Get enthalpy in kJ/kg.
    pub fn kj_per_kg(&self) -> f64 {
        self.joules_per_kg / 1000.0
    }

    /// Convert to JSON string.
    pub fn toJson(&self) -> String {
        format!(
            r#"{{"joules_per_kg":{},"kj_per_kg":{}}}"#,
            self.joules_per_kg,
            self.kj_per_kg()
        )
    }
}

impl From<Enthalpy> for WasmEnthalpy {
    fn from(h: Enthalpy) -> Self {
        WasmEnthalpy {
            joules_per_kg: h.to_joules_per_kg(),
        }
    }
}

impl From<WasmEnthalpy> for Enthalpy {
    fn from(h: WasmEnthalpy) -> Self {
        Enthalpy::from_joules_per_kg(h.joules_per_kg)
    }
}

/// Mass flow in kg/s.
#[wasm_bindgen]
#[derive(Clone, Copy, Debug)]
pub struct WasmMassFlow {
    kg_per_s: f64,
}

#[wasm_bindgen]
impl WasmMassFlow {
    /// Create mass flow from kg/s.
    #[wasm_bindgen(constructor)]
    pub fn new(kg_per_s: f64) -> Self {
        WasmMassFlow { kg_per_s }
    }

    /// Get mass flow in kg/s.
    pub fn kg_per_s(&self) -> f64 {
        self.kg_per_s
    }

    /// Convert to JSON string.
    pub fn toJson(&self) -> String {
        format!(r#"{{"kg_per_s":{}}}"#, self.kg_per_s)
    }
}

impl From<MassFlow> for WasmMassFlow {
    fn from(m: MassFlow) -> Self {
        WasmMassFlow {
            kg_per_s: m.to_kg_per_s(),
        }
    }
}

impl From<WasmMassFlow> for MassFlow {
    fn from(m: WasmMassFlow) -> Self {
        MassFlow::from_kg_per_s(m.kg_per_s)
    }
}

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

    #[wasm_bindgen_test]
    fn test_pressure_creation() {
        let p = WasmPressure::from_bar(1.0);
        assert!((p.pascals() - 100000.0).abs() < 1e-6);
        assert!((p.bar() - 1.0).abs() < 1e-9);
    }

    #[wasm_bindgen_test]
    fn test_temperature_creation() {
        let t = WasmTemperature::from_celsius(25.0);
        assert!((t.kelvin() - 298.15).abs() < 1e-6);
        assert!((t.celsius() - 25.0).abs() < 1e-9);
    }

    #[wasm_bindgen_test]
    fn test_enthalpy_creation() {
        let h = WasmEnthalpy::from_kj_per_kg(400.0);
        assert!((h.joules_per_kg() - 400000.0).abs() < 1e-6);
        assert!((h.kj_per_kg() - 400.0).abs() < 1e-9);
    }

    #[wasm_bindgen_test]
    fn test_massflow_creation() {
        let m = WasmMassFlow::new(0.1);
        assert!((m.kg_per_s() - 0.1).abs() < 1e-9);
    }
}
