use arbitrary::Arbitrary;
use compact_str::CompactString;
use std::str::FromStr;

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum AzureLocationName {
    Asia,
    AsiaPacific,
    Australia,
    AustraliaCentral,
    AustraliaCentral2,
    AustraliaEast,
    AustraliaSoutheast,
    AustriaEast,
    BelgiumCentral,
    Brazil,
    BrazilSouth,
    BrazilSoutheast,
    BrazilUS,
    Canada,
    CanadaCentral,
    CanadaEast,
    CentralIndia,
    CentralUS,
    CentralUSEUAP,
    CentralUSStage,
    ChileCentral,
    DenmarkCentral,
    DenmarkEast,
    EastAsia,
    EastAsiaStage,
    EastUS,
    EastUS2,
    EastUS2EUAP,
    EastUS2Stage,
    EastUSStage,
    EastUSSTG,
    Europe,
    France,
    FranceCentral,
    FranceSouth,
    Germany,
    GermanyNorth,
    GermanyWestCentral,
    Global,
    India,
    Indonesia,
    IndonesiaCentral,
    Israel,
    IsraelCentral,
    Italy,
    ItalyNorth,
    Japan,
    JapanEast,
    JapanWest,
    JioIndiaCentral,
    JioIndiaWest,
    Korea,
    KoreaCentral,
    KoreaSouth,
    Malaysia,
    MalaysiaWest,
    Mexico,
    MexicoCentral,
    NewZealand,
    NewZealandNorth,
    NorthCentralUS,
    NorthCentralUSStage,
    NorthEurope,
    Norway,
    NorwayEast,
    NorwayWest,
    Poland,
    PolandCentral,
    Qatar,
    QatarCentral,
    Singapore,
    SouthAfrica,
    SouthAfricaNorth,
    SouthAfricaWest,
    SouthCentralUS,
    SouthCentralUSStage,
    SouthCentralUSSTG,
    SoutheastAsia,
    SoutheastAsiaStage,
    SouthIndia,
    Spain,
    SpainCentral,
    Sweden,
    SwedenCentral,
    SwedenSouth,
    Switzerland,
    SwitzerlandNorth,
    SwitzerlandWest,
    Taiwan,
    UAE,
    UAECentral,
    UAENorth,
    UK,
    UKSouth,
    UKWest,
    UnitedArabEmirates,
    UnitedKingdom,
    UnitedStates,
    UnitedStatesEUAP,
    WestCentralUS,
    WestEurope,
    WestIndia,
    WestUS,
    WestUS2,
    WestUS2Stage,
    WestUS3,
    WestUSStage,
    Other(String),
}
impl AzureLocationName {
    pub fn is_canada(&self) -> bool {
        matches!(
            self,
            AzureLocationName::Canada
                | AzureLocationName::CanadaCentral
                | AzureLocationName::CanadaEast
        )
    }
    pub fn as_other(&self) -> Option<&str> {
        if let AzureLocationName::Other(name) = self {
            Some(name)
        } else {
            None
        }
    }
    pub const VARIANTS: &'static [AzureLocationName] = &[
        AzureLocationName::Asia,
        AzureLocationName::AsiaPacific,
        AzureLocationName::Australia,
        AzureLocationName::AustraliaCentral,
        AzureLocationName::AustraliaCentral2,
        AzureLocationName::AustraliaEast,
        AzureLocationName::AustraliaSoutheast,
        AzureLocationName::AustriaEast,
        AzureLocationName::BelgiumCentral,
        AzureLocationName::Brazil,
        AzureLocationName::BrazilSouth,
        AzureLocationName::BrazilSoutheast,
        AzureLocationName::BrazilUS,
        AzureLocationName::Canada,
        AzureLocationName::CanadaCentral,
        AzureLocationName::CanadaEast,
        AzureLocationName::CentralIndia,
        AzureLocationName::CentralUS,
        AzureLocationName::CentralUSEUAP,
        AzureLocationName::CentralUSStage,
        AzureLocationName::ChileCentral,
        AzureLocationName::DenmarkCentral,
        AzureLocationName::DenmarkEast,
        AzureLocationName::EastAsia,
        AzureLocationName::EastAsiaStage,
        AzureLocationName::EastUS,
        AzureLocationName::EastUS2,
        AzureLocationName::EastUS2EUAP,
        AzureLocationName::EastUS2Stage,
        AzureLocationName::EastUSStage,
        AzureLocationName::EastUSSTG,
        AzureLocationName::Europe,
        AzureLocationName::France,
        AzureLocationName::FranceCentral,
        AzureLocationName::FranceSouth,
        AzureLocationName::Germany,
        AzureLocationName::GermanyNorth,
        AzureLocationName::GermanyWestCentral,
        AzureLocationName::Global,
        AzureLocationName::India,
        AzureLocationName::Indonesia,
        AzureLocationName::IndonesiaCentral,
        AzureLocationName::Israel,
        AzureLocationName::IsraelCentral,
        AzureLocationName::Italy,
        AzureLocationName::ItalyNorth,
        AzureLocationName::Japan,
        AzureLocationName::JapanEast,
        AzureLocationName::JapanWest,
        AzureLocationName::JioIndiaCentral,
        AzureLocationName::JioIndiaWest,
        AzureLocationName::Korea,
        AzureLocationName::KoreaCentral,
        AzureLocationName::KoreaSouth,
        AzureLocationName::Malaysia,
        AzureLocationName::MalaysiaWest,
        AzureLocationName::Mexico,
        AzureLocationName::MexicoCentral,
        AzureLocationName::NewZealand,
        AzureLocationName::NewZealandNorth,
        AzureLocationName::NorthCentralUS,
        AzureLocationName::NorthCentralUSStage,
        AzureLocationName::NorthEurope,
        AzureLocationName::Norway,
        AzureLocationName::NorwayEast,
        AzureLocationName::NorwayWest,
        AzureLocationName::Poland,
        AzureLocationName::PolandCentral,
        AzureLocationName::Qatar,
        AzureLocationName::QatarCentral,
        AzureLocationName::Singapore,
        AzureLocationName::SouthAfrica,
        AzureLocationName::SouthAfricaNorth,
        AzureLocationName::SouthAfricaWest,
        AzureLocationName::SouthCentralUS,
        AzureLocationName::SouthCentralUSStage,
        AzureLocationName::SouthCentralUSSTG,
        AzureLocationName::SoutheastAsia,
        AzureLocationName::SoutheastAsiaStage,
        AzureLocationName::SouthIndia,
        AzureLocationName::Spain,
        AzureLocationName::SpainCentral,
        AzureLocationName::Sweden,
        AzureLocationName::SwedenCentral,
        AzureLocationName::SwedenSouth,
        AzureLocationName::Switzerland,
        AzureLocationName::SwitzerlandNorth,
        AzureLocationName::SwitzerlandWest,
        AzureLocationName::Taiwan,
        AzureLocationName::UAE,
        AzureLocationName::UAECentral,
        AzureLocationName::UAENorth,
        AzureLocationName::UK,
        AzureLocationName::UKSouth,
        AzureLocationName::UKWest,
        AzureLocationName::UnitedArabEmirates,
        AzureLocationName::UnitedKingdom,
        AzureLocationName::UnitedStates,
        AzureLocationName::UnitedStatesEUAP,
        AzureLocationName::WestCentralUS,
        AzureLocationName::WestEurope,
        AzureLocationName::WestIndia,
        AzureLocationName::WestUS,
        AzureLocationName::WestUS2,
        AzureLocationName::WestUS2Stage,
        AzureLocationName::WestUS3,
        AzureLocationName::WestUSStage,
    ];
}
impl std::fmt::Display for AzureLocationName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AzureLocationName::Other(name) => f.write_str(name),
            _ => f.write_str(&format!("{self:?}")),
        }
    }
}
impl FromStr for AzureLocationName {
    type Err = eyre::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(match s.to_ascii_lowercase().as_str() {
            "asia" => AzureLocationName::Asia,
            "asiapacific" => AzureLocationName::AsiaPacific,
            "australia" => AzureLocationName::Australia,
            "australiacentral" => AzureLocationName::AustraliaCentral,
            "australiacentral2" => AzureLocationName::AustraliaCentral2,
            "australiaeast" => AzureLocationName::AustraliaEast,
            "australiasoutheast" => AzureLocationName::AustraliaSoutheast,
            "austriaeast" => AzureLocationName::AustriaEast,
            "belgiumcentral" => AzureLocationName::BelgiumCentral,
            "brazil" => AzureLocationName::Brazil,
            "brazilsouth" => AzureLocationName::BrazilSouth,
            "brazilsoutheast" => AzureLocationName::BrazilSoutheast,
            "brazilus" => AzureLocationName::BrazilUS,
            "canada" => AzureLocationName::Canada,
            "canadacentral" => AzureLocationName::CanadaCentral,
            "canadaeast" => AzureLocationName::CanadaEast,
            "centralindia" => AzureLocationName::CentralIndia,
            "centralus" => AzureLocationName::CentralUS,
            "centraluseuap" => AzureLocationName::CentralUSEUAP,
            "centralusstage" => AzureLocationName::CentralUSStage,
            "chilecentral" => AzureLocationName::ChileCentral,
            "denmarkcentral" => AzureLocationName::DenmarkCentral,
            "denmarkeast" => AzureLocationName::DenmarkEast,
            "eastasia" => AzureLocationName::EastAsia,
            "eastasiastage" => AzureLocationName::EastAsiaStage,
            "eastus" => AzureLocationName::EastUS,
            "eastus2" => AzureLocationName::EastUS2,
            "eastus2euap" => AzureLocationName::EastUS2EUAP,
            "eastus2stage" => AzureLocationName::EastUS2Stage,
            "eastusstage" => AzureLocationName::EastUSStage,
            "eastusstg" => AzureLocationName::EastUSSTG,
            "europe" => AzureLocationName::Europe,
            "france" => AzureLocationName::France,
            "francecentral" => AzureLocationName::FranceCentral,
            "francesouth" => AzureLocationName::FranceSouth,
            "germany" => AzureLocationName::Germany,
            "germanynorth" => AzureLocationName::GermanyNorth,
            "germanywestcentral" => AzureLocationName::GermanyWestCentral,
            "global" => AzureLocationName::Global,
            "india" => AzureLocationName::India,
            "indonesia" => AzureLocationName::Indonesia,
            "indonesiacentral" => AzureLocationName::IndonesiaCentral,
            "israel" => AzureLocationName::Israel,
            "israelcentral" => AzureLocationName::IsraelCentral,
            "italy" => AzureLocationName::Italy,
            "italynorth" => AzureLocationName::ItalyNorth,
            "japan" => AzureLocationName::Japan,
            "japaneast" => AzureLocationName::JapanEast,
            "japanwest" => AzureLocationName::JapanWest,
            "jioindiacentral" => AzureLocationName::JioIndiaCentral,
            "jioindiawest" => AzureLocationName::JioIndiaWest,
            "korea" => AzureLocationName::Korea,
            "koreacentral" => AzureLocationName::KoreaCentral,
            "koreasouth" => AzureLocationName::KoreaSouth,
            "malaysia" => AzureLocationName::Malaysia,
            "malaysiawest" => AzureLocationName::MalaysiaWest,
            "mexico" => AzureLocationName::Mexico,
            "mexicocentral" => AzureLocationName::MexicoCentral,
            "newzealand" => AzureLocationName::NewZealand,
            "newzealandnorth" => AzureLocationName::NewZealandNorth,
            "northcentralus" => AzureLocationName::NorthCentralUS,
            "northcentralusstage" => AzureLocationName::NorthCentralUSStage,
            "northeurope" => AzureLocationName::NorthEurope,
            "norway" => AzureLocationName::Norway,
            "norwayeast" => AzureLocationName::NorwayEast,
            "norwaywest" => AzureLocationName::NorwayWest,
            "poland" => AzureLocationName::Poland,
            "polandcentral" => AzureLocationName::PolandCentral,
            "qatar" => AzureLocationName::Qatar,
            "qatarcentral" => AzureLocationName::QatarCentral,
            "singapore" => AzureLocationName::Singapore,
            "southafrica" => AzureLocationName::SouthAfrica,
            "southafricanorth" => AzureLocationName::SouthAfricaNorth,
            "southafricawest" => AzureLocationName::SouthAfricaWest,
            "southcentralus" => AzureLocationName::SouthCentralUS,
            "southcentralusstage" => AzureLocationName::SouthCentralUSStage,
            "southcentralusstg" => AzureLocationName::SouthCentralUSSTG,
            "southeastasia" => AzureLocationName::SoutheastAsia,
            "southeastasiastage" => AzureLocationName::SoutheastAsiaStage,
            "southindia" => AzureLocationName::SouthIndia,
            "spain" => AzureLocationName::Spain,
            "spaincentral" => AzureLocationName::SpainCentral,
            "sweden" => AzureLocationName::Sweden,
            "swedencentral" => AzureLocationName::SwedenCentral,
            "swedensouth" => AzureLocationName::SwedenSouth,
            "switzerland" => AzureLocationName::Switzerland,
            "switzerlandnorth" => AzureLocationName::SwitzerlandNorth,
            "switzerlandwest" => AzureLocationName::SwitzerlandWest,
            "taiwan" => AzureLocationName::Taiwan,
            "uae" => AzureLocationName::UAE,
            "uaecentral" => AzureLocationName::UAECentral,
            "uaenorth" => AzureLocationName::UAENorth,
            "uk" => AzureLocationName::UK,
            "uksouth" => AzureLocationName::UKSouth,
            "ukwest" => AzureLocationName::UKWest,
            "unitedarabemirates" => AzureLocationName::UnitedArabEmirates,
            "unitedkingdom" => AzureLocationName::UnitedKingdom,
            "unitedstates" => AzureLocationName::UnitedStates,
            "unitedstateseuap" => AzureLocationName::UnitedStatesEUAP,
            "westcentralus" => AzureLocationName::WestCentralUS,
            "westeurope" => AzureLocationName::WestEurope,
            "westindia" => AzureLocationName::WestIndia,
            "westus" => AzureLocationName::WestUS,
            "westus2" => AzureLocationName::WestUS2,
            "westus2stage" => AzureLocationName::WestUS2Stage,
            "westus3" => AzureLocationName::WestUS3,
            "westusstage" => AzureLocationName::WestUSStage,
            _ => AzureLocationName::Other(s.to_owned()),
        })
    }
}
impl serde::Serialize for AzureLocationName {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.to_string().serialize(serializer)
    }
}
impl<'de> serde::Deserialize<'de> for AzureLocationName {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = <CompactString as serde::Deserialize>::deserialize(deserializer)?;
        Self::from_str(&value).map_err(|e| serde::de::Error::custom(format!("{e:?}")))
    }
}
impl<'a> Arbitrary<'a> for AzureLocationName {
    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
        Ok(u.choose(AzureLocationName::VARIANTS)?.clone())
    }
}

#[cfg(test)]
mod test {
    use crate::location::AzureLocationName;

    #[test]
    pub fn it_works() -> eyre::Result<()> {
        let locations = [
            "canadacentral",
            "CanadaCentral",
            "CANADACENTRAL",
            "CanadaCENTRAL",
        ];
        let expected = AzureLocationName::CanadaCentral;
        for location in locations {
            let parsed: AzureLocationName = location.parse()?;
            assert_eq!(parsed, expected);
        }

        assert_eq!(expected.to_string(), "CanadaCentral");
        assert_eq!(serde_json::to_string(&expected)?, "\"CanadaCentral\"");
        assert_eq!(
            serde_json::from_str::<AzureLocationName>("\"canadaCENTRAL\"")?,
            expected
        );
        Ok(())
    }
}
