// SPDX-FileCopyrightText: Politik im Blick developers
// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
//
// SPDX-License-Identifier: AGPL-3.0-or-later OR EUPL-1.2

use crate::{
    BodyUrl, DateTime, Keyword, LegislativeTermUrl, Name, Url, date::Date,
    namespace::LegislativeTermNamespaceUrl,
};

#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LegislativeTerm {
    pub id: LegislativeTermUrl,

    #[serde(rename = "type")]
    pub namespace: LegislativeTermNamespaceUrl,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub body: Option<BodyUrl>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<Name>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub start_date: Option<Date>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub end_date: Option<Date>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub license: Option<Url>,

    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub keyword: Vec<Keyword>,

    pub created: DateTime,

    pub modified: DateTime,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub web: Option<Url>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub deleted: Option<bool>,

    #[serde(default, flatten)]
    pub extensions: serde_json::Map<String, serde_json::Value>,
}

#[cfg(test)]
mod serde_tests {
    use pretty_assertions::assert_eq;
    use serde_json::json;
    use time::macros::{date, datetime};

    use super::LegislativeTerm;
    use crate::namespace::LegislativeTermNamespaceUrl;

    fn example_legislative_term() -> LegislativeTerm {
        LegislativeTerm {
            id: "https://oparl.example.org/term/0"
                .parse()
                .expect("value must be parseable as id"),
            namespace: LegislativeTermNamespaceUrl::Identifier,
            body: None,
            name: Some("Gemeinderat 2021-2025".into()),
            start_date: Some(date!(2021 - 01 - 08).into()),
            end_date: Some(date!(2025 - 01 - 07).into()),
            license: None,
            keyword: vec![],
            created: datetime!(2014-01-08 14:28:31 +01:00).into(),
            modified: datetime!(2014-01-08 14:28:31 +01:00).into(),
            web: None,
            deleted: None,
            extensions: serde_json::Map::new(),
        }
    }

    fn example_legislative_term_json() -> serde_json::Value {
        json!({
            "id": "https://oparl.example.org/term/0",
            "type": "https://schema.oparl.org/1.1/LegislativeTerm",
            "name": "Gemeinderat 2021-2025",
            "startDate": "2021-01-08",
            "endDate": "2025-01-07",
            "created": "2014-01-08T14:28:31+01:00",
            "modified": "2014-01-08T14:28:31+01:00",
        })
    }

    #[test]
    fn serialize() {
        assert_eq!(
            json!(example_legislative_term()),
            example_legislative_term_json()
        );
    }

    #[test]
    fn deserialize_good() {
        let deserialized: LegislativeTerm = serde_json::from_value(example_legislative_term_json())
            .expect("value must be deserializable as LegislativeTerm");
        assert_eq!(deserialized, example_legislative_term());
    }

    #[test]
    fn deserialize_bad() {
        assert!(serde_json::from_value::<LegislativeTerm>(json!("xyzabcd")).is_err());
        assert!(serde_json::from_value::<LegislativeTerm>(json!(true)).is_err());
        assert!(serde_json::from_value::<LegislativeTerm>(json!(123)).is_err());
    }
}
