use crate::aaml::AAML;
use crate::error::AamlError;
use crate::types::Type;
use crate::types::primitive_type::PrimitiveType;
use std::fmt;

pub(crate) enum PhysicsTypes {
    Meter,
    Kilogram,
    Second,
    Ampere,
    Kelvin,
    Mole,
    Candela,
    SquareMeter,
    CubicMeter,
    MeterPerSecond,
    MeterPerSecondSquared,
    RadianPerSecond,
    RadianPerSecondSquared,
    Hertz,
    KilogramPerCubicMeter,
    KilogramMeterPerSecond,
    Newton,
    NewtonMeter,
    Pascal,
    Joule,
    Watt,
    NewtonPerMeter,
    Dimensionless,
    KilogramSquareMeter,
    JoulePerKilogramKelvin,
    JoulePerKilogram,
    JoulePerKelvin,
    Coulomb,
    Volt,
    Ohm,
    OhmMeter,
    Farad,
    VoltPerMeter,
    Tesla,
    Weber,
    Henry,
    Dioptre,
    Percentage,
    Becquerel,
    Gray,
    Sievert,
    ElectronVolt,
    Barn,
    LightYear,
    Parsec,
    AstronomicalUnit,
    HubbleConstant,
    Siemens,
    CoulombPerCubicMeter,
    CoulombPerSquareMeter,
    FaradPerMeter,
    HenryPerMeter,
    AmperePerMeter,
    AmperePerSquareMeter,
    VoltPerKelvin,
    PascalSecond,
    SquareMeterPerSecond,
    NewtonSecond,
    NewtonPerCubicMeter,
    JouleSecond,
    KilogramPerMole,
    CubicMeterPerKilogram,
    MeterPerCubicSecond,
    Lumen,
    Lux,
    LumenSecond,
    CandelaPerSquareMeter,
    WattPerSteradian,
    WattPerSquareMeter,
    WattPerMeterKelvin,
    JoulePerSquareMeter,
    Radian,
    Steradian,
    Bit,
    Decibel,
    Katal,
    MolePerCubicMeter,
    NewtonPerMeterSquared,
    JoulePerMole,
    JoulePerMoleKelvin,
    KelvinPerWatt,
    KilogramPerSecond,
    CubicMeterPerSecond,
    InverseMeter,
    NewtonPerCoulomb,
    WeberPerMeter,
    TeslaSquareMeter,
    ArcDegree,
    ArcMinute,
    ArcSecond,
    Bar,
    MillimeterOfMercury,
    Atmosphere,
    Torr,
    Poise,
    Stokes,
    Sverdrup,
    Rayl,
    Gal,
    Maxwell,
    Gauss,
    Oersted,
    Gilbert,
    Franklin,
    Debye,
    Angstrom,
    Lambert,
    Phot,
    Stilb,
    Kayser,
    Calorie,
    BritishThermalUnit,
    Langley,
    Fahrenheit,
    Celsius,
    Rankine,
    Curie,
    Roentgen,
    Rutherford,
    Fermi,
    Dalton,
    Byte,
    Baud,
    Erlang,
    MetabolicEquivalent,
    Jansky,
    MachNumber,
    Knots,
    NauticalMile,
    Horsepower,
}

impl Type for PhysicsTypes {
    fn from_name(name: &str) -> Result<Self, AamlError> {
        match name.to_lowercase().replace(['_', '-'], "").as_str() {
            // Base SI Units
            "meter" => Ok(PhysicsTypes::Meter),
            "kilogram" => Ok(PhysicsTypes::Kilogram),
            "second" => Ok(PhysicsTypes::Second),
            "ampere" => Ok(PhysicsTypes::Ampere),
            "kelvin" => Ok(PhysicsTypes::Kelvin),
            "mole" => Ok(PhysicsTypes::Mole),
            "candela" => Ok(PhysicsTypes::Candela),

            // Geometry and Space
            "squaremeter" => Ok(PhysicsTypes::SquareMeter),
            "cubicmeter" => Ok(PhysicsTypes::CubicMeter),
            "radian" => Ok(PhysicsTypes::Radian),
            "steradian" => Ok(PhysicsTypes::Steradian),
            "arcdegree" => Ok(PhysicsTypes::ArcDegree),
            "arcminute" => Ok(PhysicsTypes::ArcMinute),
            "arcsecond" => Ok(PhysicsTypes::ArcSecond),
            "angstrom" => Ok(PhysicsTypes::Angstrom),
            "inversemeter" => Ok(PhysicsTypes::InverseMeter),

            // Mechanics and Motion
            "meterpersecond" => Ok(PhysicsTypes::MeterPerSecond),
            "meterpersecondsquared" => Ok(PhysicsTypes::MeterPerSecondSquared),
            "radianpersecond" => Ok(PhysicsTypes::RadianPerSecond),
            "radianpersecondsquared" => Ok(PhysicsTypes::RadianPerSecondSquared),
            "newton" => Ok(PhysicsTypes::Newton),
            "newtonmeter" => Ok(PhysicsTypes::NewtonMeter),
            "pascal" => Ok(PhysicsTypes::Pascal),
            "joule" => Ok(PhysicsTypes::Joule),
            "watt" => Ok(PhysicsTypes::Watt),
            "hertz" => Ok(PhysicsTypes::Hertz),
            "kilogrampercubicmeter" => Ok(PhysicsTypes::KilogramPerCubicMeter),
            "kilogrammeterpersecond" => Ok(PhysicsTypes::KilogramMeterPerSecond),
            "newtonpermeter" => Ok(PhysicsTypes::NewtonPerMeter),
            "kilogramsquaremeter" => Ok(PhysicsTypes::KilogramSquareMeter),
            "pascalsecond" => Ok(PhysicsTypes::PascalSecond),
            "squaremeterpersecond" => Ok(PhysicsTypes::SquareMeterPerSecond),
            "newtonsecond" => Ok(PhysicsTypes::NewtonSecond),
            "newtonpercubicmeter" => Ok(PhysicsTypes::NewtonPerCubicMeter),
            "joulesecond" => Ok(PhysicsTypes::JouleSecond),
            "meterpercubicsecond" => Ok(PhysicsTypes::MeterPerCubicSecond),
            "kilogrampersecond" => Ok(PhysicsTypes::KilogramPerSecond),
            "cubicmeterpersecond" => Ok(PhysicsTypes::CubicMeterPerSecond),
            "newtonpermetersquared" => Ok(PhysicsTypes::NewtonPerMeterSquared),

            // Electricity and Magnetism
            "coulomb" => Ok(PhysicsTypes::Coulomb),
            "volt" => Ok(PhysicsTypes::Volt),
            "ohm" => Ok(PhysicsTypes::Ohm),
            "ohmmeter" => Ok(PhysicsTypes::OhmMeter),
            "farad" => Ok(PhysicsTypes::Farad),
            "voltpermeter" => Ok(PhysicsTypes::VoltPerMeter),
            "tesla" => Ok(PhysicsTypes::Tesla),
            "weber" => Ok(PhysicsTypes::Weber),
            "henry" => Ok(PhysicsTypes::Henry),
            "siemens" => Ok(PhysicsTypes::Siemens),
            "coulombpercubicmeter" => Ok(PhysicsTypes::CoulombPerCubicMeter),
            "coulombpersquaremeter" => Ok(PhysicsTypes::CoulombPerSquareMeter),
            "faradpermeter" => Ok(PhysicsTypes::FaradPerMeter),
            "henrypermeter" => Ok(PhysicsTypes::HenryPerMeter),
            "amperepermeter" => Ok(PhysicsTypes::AmperePerMeter),
            "amperepersquaremeter" => Ok(PhysicsTypes::AmperePerSquareMeter),
            "newtonpercoulomb" => Ok(PhysicsTypes::NewtonPerCoulomb),
            "weberpermeter" => Ok(PhysicsTypes::WeberPerMeter),
            "teslasquaremeter" => Ok(PhysicsTypes::TeslaSquareMeter),

            // Thermodynamics
            "jouleperkilogramkelvin" => Ok(PhysicsTypes::JoulePerKilogramKelvin),
            "jouleperkilogram" => Ok(PhysicsTypes::JoulePerKilogram),
            "jouleperkelvin" => Ok(PhysicsTypes::JoulePerKelvin),
            "voltperkelvin" => Ok(PhysicsTypes::VoltPerKelvin),
            "wattpermeterkelvin" => Ok(PhysicsTypes::WattPerMeterKelvin),
            "joulepermolekelvin" => Ok(PhysicsTypes::JoulePerMoleKelvin),
            "kelvinperwatt" => Ok(PhysicsTypes::KelvinPerWatt),
            "celsius" => Ok(PhysicsTypes::Celsius),
            "fahrenheit" => Ok(PhysicsTypes::Fahrenheit),
            "rankine" => Ok(PhysicsTypes::Rankine),

            // Chemistry and Particles
            "kilogrampermole" => Ok(PhysicsTypes::KilogramPerMole),
            "cubicmeterperkilogram" => Ok(PhysicsTypes::CubicMeterPerKilogram),
            "katal" => Ok(PhysicsTypes::Katal),
            "molepercubicmeter" => Ok(PhysicsTypes::MolePerCubicMeter),
            "joulepermole" => Ok(PhysicsTypes::JoulePerMole),
            "atomicmassunit" | "dalton" => Ok(PhysicsTypes::Dalton), // Dalton is a synonym for amu
            "barn" => Ok(PhysicsTypes::Barn),

            // Optics and Radiation
            "dioptre" => Ok(PhysicsTypes::Dioptre),
            "becquerel" => Ok(PhysicsTypes::Becquerel),
            "gray" => Ok(PhysicsTypes::Gray),
            "sievert" => Ok(PhysicsTypes::Sievert),
            "electronvolt" => Ok(PhysicsTypes::ElectronVolt),
            "lumen" => Ok(PhysicsTypes::Lumen),
            "lux" => Ok(PhysicsTypes::Lux),
            "lumensecond" => Ok(PhysicsTypes::LumenSecond),
            "candelapersquaremeter" => Ok(PhysicsTypes::CandelaPerSquareMeter),
            "wattpersteradian" => Ok(PhysicsTypes::WattPerSteradian),
            "wattpersquaremeter" => Ok(PhysicsTypes::WattPerSquareMeter),
            "joulepersquaremeter" => Ok(PhysicsTypes::JoulePerSquareMeter),
            "curie" => Ok(PhysicsTypes::Curie),
            "roentgen" => Ok(PhysicsTypes::Roentgen),
            "rutherford" => Ok(PhysicsTypes::Rutherford),

            // Astronomy
            "lightyear" => Ok(PhysicsTypes::LightYear),
            "parsec" => Ok(PhysicsTypes::Parsec),
            "astronomicalunit" => Ok(PhysicsTypes::AstronomicalUnit),
            "hubbleconstant" => Ok(PhysicsTypes::HubbleConstant),
            "jansky" => Ok(PhysicsTypes::Jansky),

            // Computing
            "bit" => Ok(PhysicsTypes::Bit),
            "byte" => Ok(PhysicsTypes::Byte),
            "baud" => Ok(PhysicsTypes::Baud),
            "erlang" => Ok(PhysicsTypes::Erlang),

            // Miscellaneous and Non-SI Units
            "dimensionless" => Ok(PhysicsTypes::Dimensionless),
            "percentage" => Ok(PhysicsTypes::Percentage),
            "decibel" => Ok(PhysicsTypes::Decibel),
            "bar" => Ok(PhysicsTypes::Bar),
            "millimeterofmercury" => Ok(PhysicsTypes::MillimeterOfMercury),
            "atmosphere" => Ok(PhysicsTypes::Atmosphere),
            "torr" => Ok(PhysicsTypes::Torr),
            "poise" => Ok(PhysicsTypes::Poise),
            "stokes" => Ok(PhysicsTypes::Stokes),
            "sverdrup" => Ok(PhysicsTypes::Sverdrup),
            "rayl" => Ok(PhysicsTypes::Rayl),
            "gal" => Ok(PhysicsTypes::Gal),
            "maxwell" => Ok(PhysicsTypes::Maxwell),
            "gauss" => Ok(PhysicsTypes::Gauss),
            "oersted" => Ok(PhysicsTypes::Oersted),
            "gilbert" => Ok(PhysicsTypes::Gilbert),
            "franklin" => Ok(PhysicsTypes::Franklin),
            "debye" => Ok(PhysicsTypes::Debye),
            "lambert" => Ok(PhysicsTypes::Lambert),
            "phot" => Ok(PhysicsTypes::Phot),
            "stilb" => Ok(PhysicsTypes::Stilb),
            "kayser" => Ok(PhysicsTypes::Kayser),
            "calorie" => Ok(PhysicsTypes::Calorie),
            "britishthermalunit" => Ok(PhysicsTypes::BritishThermalUnit),
            "langley" => Ok(PhysicsTypes::Langley),
            "fermi" => Ok(PhysicsTypes::Fermi),
            "metabolicequivalent" => Ok(PhysicsTypes::MetabolicEquivalent),
            "machnumber" => Ok(PhysicsTypes::MachNumber),
            "knots" => Ok(PhysicsTypes::Knots),
            "nauticalmile" => Ok(PhysicsTypes::NauticalMile),
            "horsepower" => Ok(PhysicsTypes::Horsepower),

            _ => Err(AamlError::NotFound(name.to_string())),
        }
    }

    /// Returns the recommended primitive type for storing the value of this unit.
    fn base_type(&self) -> PrimitiveType {
        match self {
            // Units typically represented as integers (counting, data sizes)
            PhysicsTypes::Bit | PhysicsTypes::Byte | PhysicsTypes::Baud => PrimitiveType::I32,

            // Most physical quantities require high precision floating point
            _ => PrimitiveType::F64,
        }
    }

    fn validate(&self, value: &str, _aaml: &AAML) -> Result<(), AamlError> {
        match self.base_type() {
            PrimitiveType::I32 => {
                value.parse::<i32>().map_err(|_| {
                    AamlError::InvalidValue(format!(
                        "Expected integer for unit {self}, got '{value}'"
                    ))
                })?;
            }
            PrimitiveType::F64 => {
                value.parse::<f64>().map_err(|_| {
                    AamlError::InvalidValue(format!(
                        "Expected number for unit {}, got '{}'",
                        self, value
                    ))
                })?;
            }
            _ => {
                return Err(AamlError::InvalidValue(format!(
                    "Unsupported base type for unit {}",
                    self
                )));
            }
        }
        Ok(())
    }
}

impl fmt::Display for PhysicsTypes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            PhysicsTypes::Meter => "meter",
            PhysicsTypes::Kilogram => "kilogram",
            PhysicsTypes::Second => "second",
            PhysicsTypes::Ampere => "ampere",
            PhysicsTypes::Kelvin => "kelvin",
            PhysicsTypes::Mole => "mole",
            PhysicsTypes::Candela => "candela",
            PhysicsTypes::SquareMeter => "squareMeter",
            PhysicsTypes::CubicMeter => "cubicMeter",
            PhysicsTypes::MeterPerSecond => "meterPerSecond",
            PhysicsTypes::MeterPerSecondSquared => "meterPerSecondSquared",
            PhysicsTypes::RadianPerSecond => "radianPerSecond",
            PhysicsTypes::RadianPerSecondSquared => "radianPerSecondSquared",
            PhysicsTypes::Hertz => "hertz",
            PhysicsTypes::KilogramPerCubicMeter => "kilogramPerCubicMeter",
            PhysicsTypes::KilogramMeterPerSecond => "kilogramMeterPerSecond",
            PhysicsTypes::Newton => "newton",
            PhysicsTypes::NewtonMeter => "newtonMeter",
            PhysicsTypes::Pascal => "pascal",
            PhysicsTypes::Joule => "joule",
            PhysicsTypes::Watt => "watt",
            PhysicsTypes::NewtonPerMeter => "newtonPerMeter",
            PhysicsTypes::Dimensionless => "dimensionless",
            PhysicsTypes::KilogramSquareMeter => "kilogramSquareMeter",
            PhysicsTypes::JoulePerKilogramKelvin => "joulePerKilogramKelvin",
            PhysicsTypes::JoulePerKilogram => "joulePerKilogram",
            PhysicsTypes::JoulePerKelvin => "joulePerKelvin",
            PhysicsTypes::Coulomb => "coulomb",
            PhysicsTypes::Volt => "volt",
            PhysicsTypes::Ohm => "ohm",
            PhysicsTypes::OhmMeter => "ohmMeter",
            PhysicsTypes::Farad => "farad",
            PhysicsTypes::VoltPerMeter => "voltPerMeter",
            PhysicsTypes::Tesla => "tesla",
            PhysicsTypes::Weber => "weber",
            PhysicsTypes::Henry => "henry",
            PhysicsTypes::Dioptre => "dioptre",
            PhysicsTypes::Percentage => "percentage",
            PhysicsTypes::Becquerel => "becquerel",
            PhysicsTypes::Gray => "gray",
            PhysicsTypes::Sievert => "sievert",
            PhysicsTypes::ElectronVolt => "electronVolt",
            PhysicsTypes::Barn => "barn",
            PhysicsTypes::LightYear => "lightYear",
            PhysicsTypes::Parsec => "parsec",
            PhysicsTypes::AstronomicalUnit => "astronomicalUnit",
            PhysicsTypes::HubbleConstant => "hubbleConstant",
            PhysicsTypes::Siemens => "siemens",
            PhysicsTypes::CoulombPerCubicMeter => "coulombPerCubicMeter",
            PhysicsTypes::CoulombPerSquareMeter => "coulombPerSquareMeter",
            PhysicsTypes::FaradPerMeter => "faradPerMeter",
            PhysicsTypes::HenryPerMeter => "henryPerMeter",
            PhysicsTypes::AmperePerMeter => "amperePerMeter",
            PhysicsTypes::AmperePerSquareMeter => "amperePerSquareMeter",
            PhysicsTypes::VoltPerKelvin => "voltPerKelvin",
            PhysicsTypes::PascalSecond => "pascalSecond",
            PhysicsTypes::SquareMeterPerSecond => "squareMeterPerSecond",
            PhysicsTypes::NewtonSecond => "newtonSecond",
            PhysicsTypes::NewtonPerCubicMeter => "newtonPerCubicMeter",
            PhysicsTypes::JouleSecond => "jouleSecond",
            PhysicsTypes::KilogramPerMole => "kilogramPerMole",
            PhysicsTypes::CubicMeterPerKilogram => "cubicMeterPerKilogram",
            PhysicsTypes::MeterPerCubicSecond => "meterPerCubicSecond",
            PhysicsTypes::Lumen => "lumen",
            PhysicsTypes::Lux => "lux",
            PhysicsTypes::LumenSecond => "lumenSecond",
            PhysicsTypes::CandelaPerSquareMeter => "candelaPerSquareMeter",
            PhysicsTypes::WattPerSteradian => "wattPerSteradian",
            PhysicsTypes::WattPerSquareMeter => "wattPerSquareMeter",
            PhysicsTypes::WattPerMeterKelvin => "wattPerMeterKelvin",
            PhysicsTypes::JoulePerSquareMeter => "joulePerSquareMeter",
            PhysicsTypes::Radian => "radian",
            PhysicsTypes::Steradian => "steradian",
            PhysicsTypes::Bit => "bit",
            PhysicsTypes::Decibel => "decibel",
            PhysicsTypes::Katal => "katal",
            PhysicsTypes::MolePerCubicMeter => "molePerCubicMeter",
            PhysicsTypes::NewtonPerMeterSquared => "newtonPerMeterSquared",
            PhysicsTypes::JoulePerMole => "joulePerMole",
            PhysicsTypes::JoulePerMoleKelvin => "joulePerMoleKelvin",
            PhysicsTypes::KelvinPerWatt => "kelvinPerWatt",
            PhysicsTypes::KilogramPerSecond => "kilogramPerSecond",
            PhysicsTypes::CubicMeterPerSecond => "cubicMeterPerSecond",
            PhysicsTypes::InverseMeter => "inverseMeter",
            PhysicsTypes::NewtonPerCoulomb => "newtonPerCoulomb",
            PhysicsTypes::WeberPerMeter => "weberPerMeter",
            PhysicsTypes::TeslaSquareMeter => "teslaSquareMeter",
            PhysicsTypes::ArcDegree => "arcDegree",
            PhysicsTypes::ArcMinute => "arcMinute",
            PhysicsTypes::ArcSecond => "arcSecond",
            PhysicsTypes::Bar => "bar",
            PhysicsTypes::MillimeterOfMercury => "millimeterOfMercury",
            PhysicsTypes::Atmosphere => "atmosphere",
            PhysicsTypes::Torr => "torr",
            PhysicsTypes::Poise => "poise",
            PhysicsTypes::Stokes => "stokes",
            PhysicsTypes::Sverdrup => "sverdrup",
            PhysicsTypes::Rayl => "rayl",
            PhysicsTypes::Gal => "gal",
            PhysicsTypes::Maxwell => "maxwell",
            PhysicsTypes::Gauss => "gauss",
            PhysicsTypes::Oersted => "oersted",
            PhysicsTypes::Gilbert => "gilbert",
            PhysicsTypes::Franklin => "franklin",
            PhysicsTypes::Debye => "debye",
            PhysicsTypes::Angstrom => "angstrom",
            PhysicsTypes::Lambert => "lambert",
            PhysicsTypes::Phot => "phot",
            PhysicsTypes::Stilb => "stilb",
            PhysicsTypes::Kayser => "kayser",
            PhysicsTypes::Calorie => "calorie",
            PhysicsTypes::BritishThermalUnit => "britishThermalUnit",
            PhysicsTypes::Langley => "langley",
            PhysicsTypes::Fahrenheit => "fahrenheit",
            PhysicsTypes::Celsius => "celsius",
            PhysicsTypes::Rankine => "rankine",
            PhysicsTypes::Curie => "curie",
            PhysicsTypes::Roentgen => "roentgen",
            PhysicsTypes::Rutherford => "rutherford",
            PhysicsTypes::Fermi => "fermi",
            PhysicsTypes::Dalton => "dalton",
            PhysicsTypes::Byte => "byte",
            PhysicsTypes::Baud => "baud",
            PhysicsTypes::Erlang => "erlang",
            PhysicsTypes::MetabolicEquivalent => "metabolicEquivalent",
            PhysicsTypes::Jansky => "jansky",
            PhysicsTypes::MachNumber => "machNumber",
            PhysicsTypes::Knots => "knots",
            PhysicsTypes::NauticalMile => "nauticalMile",
            PhysicsTypes::Horsepower => "horsepower",
        };
        write!(f, "{}", s)
    }
}
