// 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 pib_service_api_auth::user::UserInfo;
use pib_service_api_permissions::{Method, Resource};
use pib_service_api_types::body::by_id::person::{NewPerson, post::RequestBody};
use pib_service_core_types::{BodyId, PersonId};

use crate::{Backend, Result};

impl Backend {
    pub(crate) async fn body_by_id_person_post(
        &self,
        user: UserInfo,
        body_id: BodyId,
        RequestBody(NewPerson {
            name,
            family_name,
            given_name,
            form_of_address,
            affix,
            title,
            gender,
            phone,
            email,
        }): RequestBody,
    ) -> Result<PersonId> {
        self.enforce_permissions(Resource::BodyByIdPerson { body_id }, Method::POST, user.id)
            .await?;

        let mut inventory = self.inventory_provider.get_inventory().await?;
        let person = inventory
            .create_person(pib_service_inventory::NewPerson {
                body_id,
                name,
                family_name,
                given_name,
                form_of_address,
                affix,
                title,
                gender,
                phone,
                email,
            })
            .await?;
        Ok(person.id)
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use mockall::predicate::eq;
    use pib_service_api_auth::user::{Issuer, OidcSub, UserInfo};
    use pib_service_api_permissions::{Admission, Method, MockPermissions, Resource};
    use pib_service_api_types::{body::by_id::person::NewPerson, config::oidc::OidcConfig};
    use pib_service_core_types::{BodyId, PersonId, UserId};
    use pib_service_facade::Service as _;
    use pib_service_inventory::{Item, Person};
    use pib_service_test_utils::mock_inventory_with_provider;
    use pretty_assertions::assert_eq;

    use super::RequestBody;
    use crate::Backend;

    #[tokio::test]
    async fn endpoint() {
        let (inventory, provider) = mock_inventory_with_provider();
        let mut permissions = MockPermissions::new();
        let oidc = OidcConfig {
            issuer: "https://auth.example.com/".to_string(),
            client_id: "abcdef".to_string(),
            client_secret: "ghijkl".to_string(),
        };

        let user_info = UserInfo {
            id: UserId::from_u128(0x4444),
            issuer: Issuer("https://auth.example.com".to_string()),
            sub: OidcSub("theuser".to_string()),
            display_name: Some("The User".to_string()),
            is_superuser: false,
        };

        let body_id = BodyId::from_u128(0x7777);
        let person_id = PersonId::from_u128(0x9999);

        permissions
            .expect_request_permission()
            .with(
                eq(Resource::BodyByIdPerson { body_id }),
                eq(Method::POST),
                eq(user_info.id),
            )
            .times(1)
            .return_once(|_, _, _| Ok(Admission::Allow));

        let new_inventory_person = pib_service_inventory::NewPerson {
            body_id,
            name: "Dr. Pascal Muster".parse().unwrap(),
            family_name: Some("Muster".parse().unwrap()),
            given_name: Some("Pascal".parse().unwrap()),
            form_of_address: None,
            affix: None,
            title: vec!["Dr.".parse().unwrap()],
            gender: None,
            phone: vec![],
            email: vec![],
        };
        let inventory_person = Item {
            id: person_id,
            created: "2026-04-07T05:06:07+01:00".parse().unwrap(),
            modified: "2026-04-08T05:06:07+01:00".parse().unwrap(),
            value: Person {
                body_id,
                name: "Dr. Pascal Muster".parse().unwrap(),
                family_name: Some("Muster".parse().unwrap()),
                given_name: Some("Pascal".parse().unwrap()),
                form_of_address: None,
                affix: None,
                title: vec!["Dr.".parse().unwrap()],
                gender: None,
                phone: vec![],
                email: vec![],
                membership: vec![],
            },
        };

        inventory
            .write()
            .await
            .expect_create_person()
            .with(eq(new_inventory_person))
            .times(1)
            .return_once(move |_| Ok(inventory_person));

        let backend = Backend::new(provider, Arc::new(permissions), oidc, None);

        let response = backend
            .handle_body_by_id_person_post(
                user_info,
                body_id,
                RequestBody(NewPerson {
                    name: "Dr. Pascal Muster".parse().unwrap(),
                    family_name: Some("Muster".parse().unwrap()),
                    given_name: Some("Pascal".parse().unwrap()),
                    form_of_address: None,
                    affix: None,
                    title: vec!["Dr.".parse().unwrap()],
                    gender: None,
                    phone: vec![],
                    email: vec![],
                }),
            )
            .await
            .unwrap();

        assert_eq!(response, person_id);
    }
}
