// 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::{DataListLinks, Pagination};

#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DataListPage<D> {
    pub data: Vec<D>,

    pub pagination: Pagination,

    pub links: DataListLinks,

    #[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 super::DataListPage;
    use crate::{DataListLinks, Pagination};

    #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
    struct Item {
        name: String,
    }

    fn example_data_list_page() -> DataListPage<Item> {
        DataListPage {
            data: vec![
                Item {
                    name: "Item 1".into(),
                },
                Item {
                    name: "Item 2".into(),
                },
                Item {
                    name: "Item 3".into(),
                },
            ],
            pagination: Pagination {
                total_elements: Some(50000),
                elements_per_page: Some(100),
                current_page: Some(3),
                total_pages: Some(500),
                extensions: serde_json::Map::new(),
            },
            links: DataListLinks {
                first: Some(
                    "https://oparl.example.org/organization/"
                        .parse()
                        .expect("value must be parseable as url"),
                ),
                prev: Some(
                    "https://oparl.example.org/organization/?page=2"
                        .parse()
                        .expect("value must be parseable as url"),
                ),
                self_: Some(
                    "https://oparl.example.org/organization/?page=3"
                        .parse()
                        .expect("value must be parseable as url"),
                ),
                next: Some(
                    "https://oparl.example.org/organization/?page=4"
                        .parse()
                        .expect("value must be parseable as url"),
                ),
                last: Some(
                    "https://oparl.example.org/organization/?page=500"
                        .parse()
                        .expect("value must be parseable as url"),
                ),
                web: Some(
                    "https://web.example.org/organization/?page=500"
                        .parse()
                        .expect("value must be parseable as url"),
                ),
                extensions: serde_json::Map::new(),
            },
            extensions: serde_json::Map::new(),
        }
    }

    fn example_data_list_page_json() -> serde_json::Value {
        json!({
            "data": [
                {
                    "name": "Item 1"
                },
                {
                    "name": "Item 2"
                },
                {
                    "name": "Item 3"
                },
            ],
            "pagination": {
                "totalElements": 50000,
                "elementsPerPage": 100,
                "currentPage": 3,
                "totalPages":500
            },
            "links": {
                "first": "https://oparl.example.org/organization/",
                "prev": "https://oparl.example.org/organization/?page=2",
                "self": "https://oparl.example.org/organization/?page=3",
                "next": "https://oparl.example.org/organization/?page=4",
                "last": "https://oparl.example.org/organization/?page=500",
                "web": "https://web.example.org/organization/?page=500"
            }
        })
    }

    #[test]
    fn serialize() {
        assert_eq!(
            json!(example_data_list_page()),
            example_data_list_page_json()
        );
    }

    #[test]
    fn deserialize_good() {
        let deserialized: DataListPage<Item> =
            serde_json::from_value(example_data_list_page_json())
                .expect("value must be deserializable as DataListPage");
        assert_eq!(deserialized, example_data_list_page());
    }

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