#![allow(unused_qualifications)]

use crate::models;
#[cfg(any(feature = "client", feature = "server"))]
use crate::header;

/// Enumeration of values.
/// Since this enum's variants do not hold data, we can easily define them them as `#[repr(C)]`
/// which helps with FFI.
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))]
pub enum Gender {
    #[serde(rename = "MALE")]
    MALE,
    #[serde(rename = "FEMALE")]
    FEMALE,
}

impl std::fmt::Display for Gender {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match *self {
            Gender::MALE => write!(f, "{}", "MALE"),
            Gender::FEMALE => write!(f, "{}", "FEMALE"),
        }
    }
}

impl std::str::FromStr for Gender {
    type Err = String;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        match s {
            "MALE" => std::result::Result::Ok(Gender::MALE),
            "FEMALE" => std::result::Result::Ok(Gender::FEMALE),
            _ => std::result::Result::Err(format!("Value not valid: {}", s)),
        }
    }
}

/// Saint info
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
#[serde(rename = "Saint")]
pub struct Saint {
    #[serde(rename = "id")]
    #[serde(skip_serializing_if="Option::is_none")]
    pub id: Option<uuid::Uuid>,

    #[serde(rename = "displayName")]
    pub display_name: String,

    #[serde(rename = "englishName")]
    #[serde(skip_serializing_if="Option::is_none")]
    pub english_name: Option<String>,

    #[serde(rename = "frenchName")]
    #[serde(skip_serializing_if="Option::is_none")]
    pub french_name: Option<String>,

    #[serde(rename = "latinName")]
    #[serde(skip_serializing_if="Option::is_none")]
    pub latin_name: Option<String>,

    #[serde(rename = "vietnameseName")]
    pub vietnamese_name: String,

    // Note: inline enums are not fully supported by openapi-generator
    #[serde(rename = "gender")]
    pub gender: String,

    /// feast day in format DD-MM
    #[serde(rename = "feastDay")]
    pub feast_day: String,

}

impl Saint {
    pub fn new(display_name: String, vietnamese_name: String, gender: String, feast_day: String, ) -> Saint {
        Saint {
            id: None,
            display_name: display_name,
            english_name: None,
            french_name: None,
            latin_name: None,
            vietnamese_name: vietnamese_name,
            gender: gender,
            feast_day: feast_day,
        }
    }
}

/// Converts the Saint value to the Query Parameters representation (style=form, explode=false)
/// specified in https://swagger.io/docs/specification/serialization/
/// Should be implemented in a serde serializer
impl std::string::ToString for Saint {
    fn to_string(&self) -> String {
        let mut params: Vec<String> = vec![];
        // Skipping id in query parameter serialization


        params.push("displayName".to_string());
        params.push(self.display_name.to_string());


        if let Some(ref english_name) = self.english_name {
            params.push("englishName".to_string());
            params.push(english_name.to_string());
        }


        if let Some(ref french_name) = self.french_name {
            params.push("frenchName".to_string());
            params.push(french_name.to_string());
        }


        if let Some(ref latin_name) = self.latin_name {
            params.push("latinName".to_string());
            params.push(latin_name.to_string());
        }


        params.push("vietnameseName".to_string());
        params.push(self.vietnamese_name.to_string());


        params.push("gender".to_string());
        params.push(self.gender.to_string());


        params.push("feastDay".to_string());
        params.push(self.feast_day.to_string());

        params.join(",").to_string()
    }
}

/// Converts Query Parameters representation (style=form, explode=false) to a Saint value
/// as specified in https://swagger.io/docs/specification/serialization/
/// Should be implemented in a serde deserializer
impl std::str::FromStr for Saint {
    type Err = String;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        #[derive(Default)]
        // An intermediate representation of the struct to use for parsing.
        struct IntermediateRep {
            pub id: Vec<uuid::Uuid>,
            pub display_name: Vec<String>,
            pub english_name: Vec<String>,
            pub french_name: Vec<String>,
            pub latin_name: Vec<String>,
            pub vietnamese_name: Vec<String>,
            pub gender: Vec<String>,
            pub feast_day: Vec<String>,
        }

        let mut intermediate_rep = IntermediateRep::default();

        // Parse into intermediate representation
        let mut string_iter = s.split(',').into_iter();
        let mut key_result = string_iter.next();

        while key_result.is_some() {
            let val = match string_iter.next() {
                Some(x) => x,
                None => return std::result::Result::Err("Missing value while parsing Saint".to_string())
            };

            if let Some(key) = key_result {
                match key {
                    "id" => intermediate_rep.id.push(<uuid::Uuid as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "displayName" => intermediate_rep.display_name.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "englishName" => intermediate_rep.english_name.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "frenchName" => intermediate_rep.french_name.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "latinName" => intermediate_rep.latin_name.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "vietnameseName" => intermediate_rep.vietnamese_name.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "gender" => intermediate_rep.gender.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    "feastDay" => intermediate_rep.feast_day.push(<String as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    _ => return std::result::Result::Err("Unexpected key while parsing Saint".to_string())
                }
            }

            // Get the next key
            key_result = string_iter.next();
        }

        // Use the intermediate representation to return the struct
        std::result::Result::Ok(Saint {
            id: intermediate_rep.id.into_iter().next(),
            display_name: intermediate_rep.display_name.into_iter().next().ok_or("displayName missing in Saint".to_string())?,
            english_name: intermediate_rep.english_name.into_iter().next(),
            french_name: intermediate_rep.french_name.into_iter().next(),
            latin_name: intermediate_rep.latin_name.into_iter().next(),
            vietnamese_name: intermediate_rep.vietnamese_name.into_iter().next().ok_or("vietnameseName missing in Saint".to_string())?,
            gender: intermediate_rep.gender.into_iter().next().ok_or("gender missing in Saint".to_string())?,
            feast_day: intermediate_rep.feast_day.into_iter().next().ok_or("feastDay missing in Saint".to_string())?,
        })
    }
}

// Methods for converting between header::IntoHeaderValue<Saint> and hyper::header::HeaderValue

#[cfg(any(feature = "client", feature = "server"))]
impl std::convert::TryFrom<header::IntoHeaderValue<Saint>> for hyper::header::HeaderValue {
    type Error = String;

    fn try_from(hdr_value: header::IntoHeaderValue<Saint>) -> std::result::Result<Self, Self::Error> {
        let hdr_value = hdr_value.to_string();
        match hyper::header::HeaderValue::from_str(&hdr_value) {
             std::result::Result::Ok(value) => std::result::Result::Ok(value),
             std::result::Result::Err(e) => std::result::Result::Err(
                 format!("Invalid header value for Saint - value: {} is invalid {}",
                     hdr_value, e))
        }
    }
}

#[cfg(any(feature = "client", feature = "server"))]
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<Saint> {
    type Error = String;

    fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> {
        match hdr_value.to_str() {
             std::result::Result::Ok(value) => {
                    match <Saint as std::str::FromStr>::from_str(value) {
                        std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)),
                        std::result::Result::Err(err) => std::result::Result::Err(
                            format!("Unable to convert header value '{}' into Saint - {}",
                                value, err))
                    }
             },
             std::result::Result::Err(e) => std::result::Result::Err(
                 format!("Unable to convert header: {:?} to string: {}",
                     hdr_value, e))
        }
    }
}


#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))]
pub struct SaintCollection {
    #[serde(rename = "saints")]
    #[serde(skip_serializing_if="Option::is_none")]
    pub saints: Option<Vec<models::Saint>>,

    #[serde(rename = "hasMore")]
    #[serde(skip_serializing_if="Option::is_none")]
    pub has_more: Option<bool>,

}

impl SaintCollection {
    pub fn new() -> SaintCollection {
        SaintCollection {
            saints: None,
            has_more: None,
        }
    }
}

/// Converts the SaintCollection value to the Query Parameters representation (style=form, explode=false)
/// specified in https://swagger.io/docs/specification/serialization/
/// Should be implemented in a serde serializer
impl std::string::ToString for SaintCollection {
    fn to_string(&self) -> String {
        let mut params: Vec<String> = vec![];
        // Skipping saints in query parameter serialization


        if let Some(ref has_more) = self.has_more {
            params.push("hasMore".to_string());
            params.push(has_more.to_string());
        }

        params.join(",").to_string()
    }
}

/// Converts Query Parameters representation (style=form, explode=false) to a SaintCollection value
/// as specified in https://swagger.io/docs/specification/serialization/
/// Should be implemented in a serde deserializer
impl std::str::FromStr for SaintCollection {
    type Err = String;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        #[derive(Default)]
        // An intermediate representation of the struct to use for parsing.
        struct IntermediateRep {
            pub saints: Vec<Vec<models::Saint>>,
            pub has_more: Vec<bool>,
        }

        let mut intermediate_rep = IntermediateRep::default();

        // Parse into intermediate representation
        let mut string_iter = s.split(',').into_iter();
        let mut key_result = string_iter.next();

        while key_result.is_some() {
            let val = match string_iter.next() {
                Some(x) => x,
                None => return std::result::Result::Err("Missing value while parsing SaintCollection".to_string())
            };

            if let Some(key) = key_result {
                match key {
                    "saints" => return std::result::Result::Err("Parsing a container in this style is not supported in SaintCollection".to_string()),
                    "hasMore" => intermediate_rep.has_more.push(<bool as std::str::FromStr>::from_str(val).map_err(|x| format!("{}", x))?),
                    _ => return std::result::Result::Err("Unexpected key while parsing SaintCollection".to_string())
                }
            }

            // Get the next key
            key_result = string_iter.next();
        }

        // Use the intermediate representation to return the struct
        std::result::Result::Ok(SaintCollection {
            saints: intermediate_rep.saints.into_iter().next(),
            has_more: intermediate_rep.has_more.into_iter().next(),
        })
    }
}

// Methods for converting between header::IntoHeaderValue<SaintCollection> and hyper::header::HeaderValue

#[cfg(any(feature = "client", feature = "server"))]
impl std::convert::TryFrom<header::IntoHeaderValue<SaintCollection>> for hyper::header::HeaderValue {
    type Error = String;

    fn try_from(hdr_value: header::IntoHeaderValue<SaintCollection>) -> std::result::Result<Self, Self::Error> {
        let hdr_value = hdr_value.to_string();
        match hyper::header::HeaderValue::from_str(&hdr_value) {
             std::result::Result::Ok(value) => std::result::Result::Ok(value),
             std::result::Result::Err(e) => std::result::Result::Err(
                 format!("Invalid header value for SaintCollection - value: {} is invalid {}",
                     hdr_value, e))
        }
    }
}

#[cfg(any(feature = "client", feature = "server"))]
impl std::convert::TryFrom<hyper::header::HeaderValue> for header::IntoHeaderValue<SaintCollection> {
    type Error = String;

    fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result<Self, Self::Error> {
        match hdr_value.to_str() {
             std::result::Result::Ok(value) => {
                    match <SaintCollection as std::str::FromStr>::from_str(value) {
                        std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)),
                        std::result::Result::Err(err) => std::result::Result::Err(
                            format!("Unable to convert header value '{}' into SaintCollection - {}",
                                value, err))
                    }
             },
             std::result::Result::Err(e) => std::result::Result::Err(
                 format!("Unable to convert header: {:?} to string: {}",
                     hdr_value, e))
        }
    }
}

