use std::{fmt, str};

#[cfg(feature = "diesel")]
use diesel::{deserialize, pg::Pg, serialize, sql_types};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "diesel", derive(AsExpression, FromSqlRow))]
#[cfg_attr(feature = "diesel", sql_type = "diesel::sql_types::Text")]
pub enum Country {
    AC,
    AD,
    AE,
    AF,
    AG,
    AI,
    AL,
    AM,
    AO,
    AQ,
    AR,
    AS,
    AT,
    AU,
    AW,
    AX,
    AZ,
    BA,
    BB,
    BD,
    BE,
    BF,
    BG,
    BH,
    BI,
    BJ,
    BL,
    BM,
    BN,
    BO,
    BQ,
    BR,
    BS,
    BT,
    BV,
    BW,
    BY,
    BZ,
    CA,
    CC,
    CD,
    CF,
    CG,
    CH,
    CI,
    CK,
    CL,
    CM,
    CN,
    CO,
    CR,
    CU,
    CV,
    CW,
    CX,
    CY,
    CZ,
    DE,
    DG,
    DJ,
    DK,
    DM,
    DO,
    DZ,
    EA,
    EC,
    EE,
    EG,
    EH,
    ER,
    ES,
    ET,
    FI,
    FJ,
    FK,
    FM,
    FO,
    FR,
    GA,
    GB,
    GD,
    GE,
    GF,
    GG,
    GH,
    GI,
    GL,
    GM,
    GN,
    GP,
    GQ,
    GR,
    GS,
    GT,
    GU,
    GW,
    GY,
    HK,
    HM,
    HN,
    HR,
    HT,
    HU,
    IC,
    ID,
    IE,
    IL,
    IM,
    IN,
    IO,
    IQ,
    IR,
    IS,
    IT,
    JE,
    JM,
    JO,
    JP,
    KE,
    KG,
    KH,
    KI,
    KM,
    KN,
    KP,
    KR,
    KW,
    KY,
    KZ,
    LA,
    LB,
    LC,
    LI,
    LK,
    LR,
    LS,
    LT,
    LU,
    LV,
    LY,
    MA,
    MC,
    MD,
    ME,
    MF,
    MG,
    MH,
    MK,
    ML,
    MM,
    MN,
    MO,
    MP,
    MQ,
    MR,
    MS,
    MT,
    MU,
    MV,
    MW,
    MX,
    MY,
    MZ,
    NA,
    NC,
    NE,
    NF,
    NG,
    NI,
    NL,
    NO,
    NP,
    NR,
    NU,
    NZ,
    OM,
    PA,
    PE,
    PF,
    PG,
    PH,
    PK,
    PL,
    PM,
    PN,
    PR,
    PS,
    PT,
    PW,
    PY,
    QA,
    RE,
    RO,
    RS,
    RU,
    RW,
    SA,
    SB,
    SC,
    SD,
    SE,
    SG,
    SH,
    SI,
    SJ,
    SK,
    SL,
    SM,
    SN,
    SO,
    SR,
    SS,
    ST,
    SV,
    SX,
    SY,
    SZ,
    TA,
    TC,
    TD,
    TF,
    TG,
    TH,
    TJ,
    TK,
    TL,
    TM,
    TN,
    TO,
    TR,
    TT,
    TV,
    TW,
    TZ,
    UA,
    UG,
    UM,
    US,
    UY,
    UZ,
    VA,
    VC,
    VE,
    VG,
    VI,
    VN,
    VU,
    WF,
    WS,
    XK,
    YE,
    YT,
    ZA,
    ZM,
    ZW,
}

impl fmt::Display for Country {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

#[cfg(feature = "diesel")]
impl serialize::ToSql<sql_types::Varchar, Pg> for Country {
    fn to_sql<W: std::io::Write>(
        &self,
        out: &mut serialize::Output<'_, W, Pg>,
    ) -> serialize::Result {
        let s = self.to_string();
        serialize::ToSql::<sql_types::Varchar, Pg>::to_sql(&s, out)
    }
}

#[cfg(feature = "diesel")]
impl deserialize::FromSql<sql_types::Varchar, Pg> for Country {
    fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
        let bytes = not_none!(bytes);

        match str::from_utf8(bytes)? {
            "AC" => Ok(Country::AC),
            "AD" => Ok(Country::AD),
            "AE" => Ok(Country::AE),
            "AF" => Ok(Country::AF),
            "AG" => Ok(Country::AG),
            "AI" => Ok(Country::AI),
            "AL" => Ok(Country::AL),
            "AM" => Ok(Country::AM),
            "AO" => Ok(Country::AO),
            "AQ" => Ok(Country::AQ),
            "AR" => Ok(Country::AR),
            "AS" => Ok(Country::AS),
            "AT" => Ok(Country::AT),
            "AU" => Ok(Country::AU),
            "AW" => Ok(Country::AW),
            "AX" => Ok(Country::AX),
            "AZ" => Ok(Country::AZ),
            "BA" => Ok(Country::BA),
            "BB" => Ok(Country::BB),
            "BD" => Ok(Country::BD),
            "BE" => Ok(Country::BE),
            "BF" => Ok(Country::BF),
            "BG" => Ok(Country::BG),
            "BH" => Ok(Country::BH),
            "BI" => Ok(Country::BI),
            "BJ" => Ok(Country::BJ),
            "BL" => Ok(Country::BL),
            "BM" => Ok(Country::BM),
            "BN" => Ok(Country::BN),
            "BO" => Ok(Country::BO),
            "BQ" => Ok(Country::BQ),
            "BR" => Ok(Country::BR),
            "BS" => Ok(Country::BS),
            "BT" => Ok(Country::BT),
            "BW" => Ok(Country::BW),
            "BY" => Ok(Country::BY),
            "BZ" => Ok(Country::BZ),
            "CA" => Ok(Country::CA),
            "CC" => Ok(Country::CC),
            "CD" => Ok(Country::CD),
            "CF" => Ok(Country::CF),
            "CG" => Ok(Country::CG),
            "CH" => Ok(Country::CH),
            "CI" => Ok(Country::CI),
            "CK" => Ok(Country::CK),
            "CL" => Ok(Country::CL),
            "CM" => Ok(Country::CM),
            "CN" => Ok(Country::CN),
            "CO" => Ok(Country::CO),
            "CR" => Ok(Country::CR),
            "CU" => Ok(Country::CU),
            "CV" => Ok(Country::CV),
            "CW" => Ok(Country::CW),
            "CX" => Ok(Country::CX),
            "CY" => Ok(Country::CY),
            "CZ" => Ok(Country::CZ),
            "DE" => Ok(Country::DE),
            "DG" => Ok(Country::DG),
            "DJ" => Ok(Country::DJ),
            "DK" => Ok(Country::DK),
            "DM" => Ok(Country::DM),
            "DO" => Ok(Country::DO),
            "DZ" => Ok(Country::DZ),
            "EA" => Ok(Country::EA),
            "EC" => Ok(Country::EC),
            "EE" => Ok(Country::EE),
            "EG" => Ok(Country::EG),
            "EH" => Ok(Country::EH),
            "ER" => Ok(Country::ER),
            "ES" => Ok(Country::ES),
            "ET" => Ok(Country::ET),
            "FI" => Ok(Country::FI),
            "FJ" => Ok(Country::FJ),
            "FK" => Ok(Country::FK),
            "FM" => Ok(Country::FM),
            "FO" => Ok(Country::FO),
            "FR" => Ok(Country::FR),
            "GA" => Ok(Country::GA),
            "GB" => Ok(Country::GB),
            "GD" => Ok(Country::GD),
            "GE" => Ok(Country::GE),
            "GF" => Ok(Country::GF),
            "GG" => Ok(Country::GG),
            "GH" => Ok(Country::GH),
            "GI" => Ok(Country::GI),
            "GL" => Ok(Country::GL),
            "GM" => Ok(Country::GM),
            "GN" => Ok(Country::GN),
            "GP" => Ok(Country::GP),
            "GQ" => Ok(Country::GQ),
            "GR" => Ok(Country::GR),
            "GS" => Ok(Country::GS),
            "GT" => Ok(Country::GT),
            "GU" => Ok(Country::GU),
            "GW" => Ok(Country::GW),
            "GY" => Ok(Country::GY),
            "HK" => Ok(Country::HK),
            "HN" => Ok(Country::HN),
            "HR" => Ok(Country::HR),
            "HT" => Ok(Country::HT),
            "HU" => Ok(Country::HU),
            "IC" => Ok(Country::IC),
            "ID" => Ok(Country::ID),
            "IE" => Ok(Country::IE),
            "IL" => Ok(Country::IL),
            "IM" => Ok(Country::IM),
            "IN" => Ok(Country::IN),
            "IO" => Ok(Country::IO),
            "IQ" => Ok(Country::IQ),
            "IR" => Ok(Country::IR),
            "IS" => Ok(Country::IS),
            "IT" => Ok(Country::IT),
            "JE" => Ok(Country::JE),
            "JM" => Ok(Country::JM),
            "JO" => Ok(Country::JO),
            "JP" => Ok(Country::JP),
            "KE" => Ok(Country::KE),
            "KG" => Ok(Country::KG),
            "KH" => Ok(Country::KH),
            "KI" => Ok(Country::KI),
            "KM" => Ok(Country::KM),
            "KN" => Ok(Country::KN),
            "KP" => Ok(Country::KP),
            "KR" => Ok(Country::KR),
            "KW" => Ok(Country::KW),
            "KY" => Ok(Country::KY),
            "KZ" => Ok(Country::KZ),
            "LA" => Ok(Country::LA),
            "LB" => Ok(Country::LB),
            "LC" => Ok(Country::LC),
            "LI" => Ok(Country::LI),
            "LK" => Ok(Country::LK),
            "LR" => Ok(Country::LR),
            "LS" => Ok(Country::LS),
            "LT" => Ok(Country::LT),
            "LU" => Ok(Country::LU),
            "LV" => Ok(Country::LV),
            "LY" => Ok(Country::LY),
            "MA" => Ok(Country::MA),
            "MC" => Ok(Country::MC),
            "MD" => Ok(Country::MD),
            "ME" => Ok(Country::ME),
            "MF" => Ok(Country::MF),
            "MG" => Ok(Country::MG),
            "MH" => Ok(Country::MH),
            "MK" => Ok(Country::MK),
            "ML" => Ok(Country::ML),
            "MM" => Ok(Country::MM),
            "MN" => Ok(Country::MN),
            "MO" => Ok(Country::MO),
            "MP" => Ok(Country::MP),
            "MQ" => Ok(Country::MQ),
            "MR" => Ok(Country::MR),
            "MS" => Ok(Country::MS),
            "MT" => Ok(Country::MT),
            "MU" => Ok(Country::MU),
            "MV" => Ok(Country::MV),
            "MW" => Ok(Country::MW),
            "MX" => Ok(Country::MX),
            "MY" => Ok(Country::MY),
            "MZ" => Ok(Country::MZ),
            "NA" => Ok(Country::NA),
            "NC" => Ok(Country::NC),
            "NE" => Ok(Country::NE),
            "NF" => Ok(Country::NF),
            "NG" => Ok(Country::NG),
            "NI" => Ok(Country::NI),
            "NL" => Ok(Country::NL),
            "NO" => Ok(Country::NO),
            "NP" => Ok(Country::NP),
            "NR" => Ok(Country::NR),
            "NU" => Ok(Country::NU),
            "NZ" => Ok(Country::NZ),
            "OM" => Ok(Country::OM),
            "PA" => Ok(Country::PA),
            "PE" => Ok(Country::PE),
            "PF" => Ok(Country::PF),
            "PG" => Ok(Country::PG),
            "PH" => Ok(Country::PH),
            "PK" => Ok(Country::PK),
            "PL" => Ok(Country::PL),
            "PM" => Ok(Country::PM),
            "PN" => Ok(Country::PN),
            "PR" => Ok(Country::PR),
            "PS" => Ok(Country::PS),
            "PT" => Ok(Country::PT),
            "PW" => Ok(Country::PW),
            "PY" => Ok(Country::PY),
            "QA" => Ok(Country::QA),
            "RE" => Ok(Country::RE),
            "RO" => Ok(Country::RO),
            "RS" => Ok(Country::RS),
            "RU" => Ok(Country::RU),
            "RW" => Ok(Country::RW),
            "SA" => Ok(Country::SA),
            "SB" => Ok(Country::SB),
            "SC" => Ok(Country::SC),
            "SD" => Ok(Country::SD),
            "SE" => Ok(Country::SE),
            "SG" => Ok(Country::SG),
            "SH" => Ok(Country::SH),
            "SI" => Ok(Country::SI),
            "SJ" => Ok(Country::SJ),
            "SK" => Ok(Country::SK),
            "SL" => Ok(Country::SL),
            "SM" => Ok(Country::SM),
            "SN" => Ok(Country::SN),
            "SO" => Ok(Country::SO),
            "SR" => Ok(Country::SR),
            "SS" => Ok(Country::SS),
            "ST" => Ok(Country::ST),
            "SV" => Ok(Country::SV),
            "SX" => Ok(Country::SX),
            "SY" => Ok(Country::SY),
            "SZ" => Ok(Country::SZ),
            "TA" => Ok(Country::TA),
            "TC" => Ok(Country::TC),
            "TD" => Ok(Country::TD),
            "TF" => Ok(Country::TF),
            "TG" => Ok(Country::TG),
            "TH" => Ok(Country::TH),
            "TJ" => Ok(Country::TJ),
            "TK" => Ok(Country::TK),
            "TL" => Ok(Country::TL),
            "TM" => Ok(Country::TM),
            "TN" => Ok(Country::TN),
            "TO" => Ok(Country::TO),
            "TR" => Ok(Country::TR),
            "TT" => Ok(Country::TT),
            "TV" => Ok(Country::TV),
            "TW" => Ok(Country::TW),
            "TZ" => Ok(Country::TZ),
            "UA" => Ok(Country::UA),
            "UG" => Ok(Country::UG),
            "UM" => Ok(Country::UM),
            "US" => Ok(Country::US),
            "UY" => Ok(Country::UY),
            "UZ" => Ok(Country::UZ),
            "VA" => Ok(Country::VA),
            "VC" => Ok(Country::VC),
            "VE" => Ok(Country::VE),
            "VG" => Ok(Country::VG),
            "VI" => Ok(Country::VI),
            "VN" => Ok(Country::VN),
            "VU" => Ok(Country::VU),
            "WF" => Ok(Country::WF),
            "WS" => Ok(Country::WS),
            "XK" => Ok(Country::XK),
            "YE" => Ok(Country::YE),
            "YT" => Ok(Country::YT),
            "ZA" => Ok(Country::ZA),
            "ZM" => Ok(Country::ZM),
            "ZW" => Ok(Country::ZW),
            s => Err(format!("Unknown country code {}", s).into()),
        }
    }
}

impl AsRef<str> for Country {
    fn as_ref(&self) -> &str {
        match self {
            Country::AC => "AC",
            Country::AD => "AD",
            Country::AE => "AE",
            Country::AF => "AF",
            Country::AG => "AG",
            Country::AI => "AI",
            Country::AL => "AL",
            Country::AM => "AM",
            Country::AO => "AO",
            Country::AQ => "AQ",
            Country::AR => "AR",
            Country::AS => "AS",
            Country::AT => "AT",
            Country::AU => "AU",
            Country::AW => "AW",
            Country::AX => "AX",
            Country::AZ => "AZ",
            Country::BA => "BA",
            Country::BB => "BB",
            Country::BD => "BD",
            Country::BE => "BE",
            Country::BF => "BF",
            Country::BG => "BG",
            Country::BH => "BH",
            Country::BI => "BI",
            Country::BJ => "BJ",
            Country::BL => "BL",
            Country::BM => "BM",
            Country::BN => "BN",
            Country::BO => "BO",
            Country::BQ => "BQ",
            Country::BR => "BR",
            Country::BS => "BS",
            Country::BT => "BT",
            Country::BV => "BV",
            Country::BW => "BW",
            Country::BY => "BY",
            Country::BZ => "BZ",
            Country::CA => "CA",
            Country::CC => "CC",
            Country::CD => "CD",
            Country::CF => "CF",
            Country::CG => "CG",
            Country::CH => "CH",
            Country::CI => "CI",
            Country::CK => "CK",
            Country::CL => "CL",
            Country::CM => "CM",
            Country::CN => "CN",
            Country::CO => "CO",
            Country::CR => "CR",
            Country::CU => "CU",
            Country::CV => "CV",
            Country::CW => "CW",
            Country::CX => "CX",
            Country::CY => "CY",
            Country::CZ => "CZ",
            Country::DE => "DE",
            Country::DG => "DG",
            Country::DJ => "DJ",
            Country::DK => "DK",
            Country::DM => "DM",
            Country::DO => "DO",
            Country::DZ => "DZ",
            Country::EA => "EA",
            Country::EC => "EC",
            Country::EE => "EE",
            Country::EG => "EG",
            Country::EH => "EH",
            Country::ER => "ER",
            Country::ES => "ES",
            Country::ET => "ET",
            Country::FI => "FI",
            Country::FJ => "FJ",
            Country::FK => "FK",
            Country::FM => "FM",
            Country::FO => "FO",
            Country::FR => "FR",
            Country::GA => "GA",
            Country::GB => "GB",
            Country::GD => "GD",
            Country::GE => "GE",
            Country::GF => "GF",
            Country::GG => "GG",
            Country::GH => "GH",
            Country::GI => "GI",
            Country::GL => "GL",
            Country::GM => "GM",
            Country::GN => "GN",
            Country::GP => "GP",
            Country::GQ => "GQ",
            Country::GR => "GR",
            Country::GS => "GS",
            Country::GT => "GT",
            Country::GU => "GU",
            Country::GW => "GW",
            Country::GY => "GY",
            Country::HK => "HK",
            Country::HM => "HM",
            Country::HN => "HN",
            Country::HR => "HR",
            Country::HT => "HT",
            Country::HU => "HU",
            Country::IC => "IC",
            Country::ID => "ID",
            Country::IE => "IE",
            Country::IL => "IL",
            Country::IM => "IM",
            Country::IN => "IN",
            Country::IO => "IO",
            Country::IQ => "IQ",
            Country::IR => "IR",
            Country::IS => "IS",
            Country::IT => "IT",
            Country::JE => "JE",
            Country::JM => "JM",
            Country::JO => "JO",
            Country::JP => "JP",
            Country::KE => "KE",
            Country::KG => "KG",
            Country::KH => "KH",
            Country::KI => "KI",
            Country::KM => "KM",
            Country::KN => "KN",
            Country::KP => "KP",
            Country::KR => "KR",
            Country::KW => "KW",
            Country::KY => "KY",
            Country::KZ => "KZ",
            Country::LA => "LA",
            Country::LB => "LB",
            Country::LC => "LC",
            Country::LI => "LI",
            Country::LK => "LK",
            Country::LR => "LR",
            Country::LS => "LS",
            Country::LT => "LT",
            Country::LU => "LU",
            Country::LV => "LV",
            Country::LY => "LY",
            Country::MA => "MA",
            Country::MC => "MC",
            Country::MD => "MD",
            Country::ME => "ME",
            Country::MF => "MF",
            Country::MG => "MG",
            Country::MH => "MH",
            Country::MK => "MK",
            Country::ML => "ML",
            Country::MM => "MM",
            Country::MN => "MN",
            Country::MO => "MO",
            Country::MP => "MP",
            Country::MQ => "MQ",
            Country::MR => "MR",
            Country::MS => "MS",
            Country::MT => "MT",
            Country::MU => "MU",
            Country::MV => "MV",
            Country::MW => "MW",
            Country::MX => "MX",
            Country::MY => "MY",
            Country::MZ => "MZ",
            Country::NA => "NA",
            Country::NC => "NC",
            Country::NE => "NE",
            Country::NF => "NF",
            Country::NG => "NG",
            Country::NI => "NI",
            Country::NL => "NL",
            Country::NO => "NO",
            Country::NP => "NP",
            Country::NR => "NR",
            Country::NU => "NU",
            Country::NZ => "NZ",
            Country::OM => "OM",
            Country::PA => "PA",
            Country::PE => "PE",
            Country::PF => "PF",
            Country::PG => "PG",
            Country::PH => "PH",
            Country::PK => "PK",
            Country::PL => "PL",
            Country::PM => "PM",
            Country::PN => "PN",
            Country::PR => "PR",
            Country::PS => "PS",
            Country::PT => "PT",
            Country::PW => "PW",
            Country::PY => "PY",
            Country::QA => "QA",
            Country::RE => "RE",
            Country::RO => "RO",
            Country::RS => "RS",
            Country::RU => "RU",
            Country::RW => "RW",
            Country::SA => "SA",
            Country::SB => "SB",
            Country::SC => "SC",
            Country::SD => "SD",
            Country::SE => "SE",
            Country::SG => "SG",
            Country::SH => "SH",
            Country::SI => "SI",
            Country::SJ => "SJ",
            Country::SK => "SK",
            Country::SL => "SL",
            Country::SM => "SM",
            Country::SN => "SN",
            Country::SO => "SO",
            Country::SR => "SR",
            Country::SS => "SS",
            Country::ST => "ST",
            Country::SV => "SV",
            Country::SX => "SX",
            Country::SY => "SY",
            Country::SZ => "SZ",
            Country::TA => "TA",
            Country::TC => "TC",
            Country::TD => "TD",
            Country::TF => "TF",
            Country::TG => "TG",
            Country::TH => "TH",
            Country::TJ => "TJ",
            Country::TK => "TK",
            Country::TL => "TL",
            Country::TM => "TM",
            Country::TN => "TN",
            Country::TO => "TO",
            Country::TR => "TR",
            Country::TT => "TT",
            Country::TV => "TV",
            Country::TW => "TW",
            Country::TZ => "TZ",
            Country::UA => "UA",
            Country::UG => "UG",
            Country::UM => "UM",
            Country::US => "US",
            Country::UY => "UY",
            Country::UZ => "UZ",
            Country::VA => "VA",
            Country::VC => "VC",
            Country::VE => "VE",
            Country::VG => "VG",
            Country::VI => "VI",
            Country::VN => "VN",
            Country::VU => "VU",
            Country::WF => "WF",
            Country::WS => "WS",
            Country::XK => "XK",
            Country::YE => "YE",
            Country::YT => "YT",
            Country::ZA => "ZA",
            Country::ZM => "ZM",
            Country::ZW => "ZW",
        }
    }
}

#[cfg(test)]
mod test {
    use super::Country;
    use serde_json as json;

    #[test]
    fn json_serialize() {
        assert_eq!(json::to_string(&Country::DE).unwrap(), r#""DE""#);
    }

    #[test]
    fn json_deserialize() {
        let country: Country = json::from_str(r#""DE""#).unwrap();
        assert_eq!(country, Country::DE);
    }

    // #[test]
    // fn from_str() {
    //     use std::str::FromStr;
    //     use strum::ParseError::VariantNotFound;

    //     assert_eq!(Country::from_str("DE").unwrap(), Country::DE);
    //     assert_eq!(Country::from_str("de"), Err(VariantNotFound));
    // }

    // #[test]
    // fn to_string() {
    //     use std::string::ToString;

    //     assert_eq!(Country::DE.to_string(), "DE");
    // }
}
