use sciforge::hub::domain::common::constants::SIGMA_SB;
use sciforge::hub::domain::meteorology::radiation::{
    planck_function, solar_zenith_angle, stefan_boltzmann_flux,
};

pub struct MercuryThermalState {
    pub distance_au: f64,
    pub albedo: f64,
}

impl MercuryThermalState {
    pub fn mean() -> Self {
        Self {
            distance_au: 0.387,
            albedo: crate::BOND_ALBEDO,
        }
    }

    pub fn at_perihelion() -> Self {
        Self {
            distance_au: 0.307,
            albedo: crate::BOND_ALBEDO,
        }
    }

    pub fn at_aphelion() -> Self {
        Self {
            distance_au: 0.467,
            albedo: crate::BOND_ALBEDO,
        }
    }

    pub fn at_distance(distance_au: f64) -> Self {
        Self {
            distance_au,
            albedo: crate::BOND_ALBEDO,
        }
    }

    pub fn solar_flux(&self) -> f64 {
        sciforge::hub::domain::meteorology::radiation::solar_constant()
            / (self.distance_au * self.distance_au)
    }

    pub fn subsolar_temperature_k(&self) -> f64 {
        let flux = self.solar_flux() * (1.0 - self.albedo);
        (flux / SIGMA_SB).powf(0.25)
    }

    pub fn temperature_at_zenith_k(&self, zenith_deg: f64) -> f64 {
        if zenith_deg >= 90.0 {
            return crate::NIGHTSIDE_TEMP_K;
        }
        let cos_z = zenith_deg.to_radians().cos();
        let flux = self.solar_flux() * (1.0 - self.albedo) * cos_z;
        (flux / SIGMA_SB).powf(0.25)
    }

    pub fn outgoing_radiation(&self, temperature_k: f64) -> f64 {
        crate::SURFACE_EMISSIVITY * stefan_boltzmann_flux(temperature_k)
    }

    pub fn effective_temperature_k(&self) -> f64 {
        let s = self.solar_flux();
        ((s * (1.0 - self.albedo)) / (4.0 * SIGMA_SB)).powf(0.25)
    }

    pub fn greenhouse_effect_k(&self) -> f64 {
        0.0
    }

    pub fn energy_imbalance(&self, surface_temp_k: f64) -> f64 {
        let absorbed = self.solar_flux() * (1.0 - self.albedo) / 4.0;
        let emitted = crate::SURFACE_EMISSIVITY * stefan_boltzmann_flux(surface_temp_k);
        absorbed - emitted
    }
}

pub fn solar_zenith(latitude_deg: f64, declination_deg: f64, hour_angle_deg: f64) -> f64 {
    solar_zenith_angle(latitude_deg, declination_deg, hour_angle_deg)
}

pub fn planck_spectral_radiance(wavelength_m: f64, temperature_k: f64) -> f64 {
    planck_function(wavelength_m, temperature_k)
}

pub fn wien_peak_wavelength(temperature_k: f64) -> f64 {
    2.898e-3 / temperature_k
}

pub fn equatorial_temp_range() -> (f64, f64) {
    (crate::NIGHTSIDE_TEMP_K, crate::SUBSOLAR_TEMP_K)
}

pub fn polar_cold_trap_temp() -> f64 {
    crate::POLAR_COLD_TRAP_TEMP_K
}
