// 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 std::sync::Arc;

use axum::{
    Extension, Json,
    extract::{Path, State},
    response::Redirect,
};
use pib_service_api_auth::user::UserInfo;
use pib_service_api_types::body::by_id::organization::by_id::patch::RequestBody;
use pib_service_core_types::{BodyId, OrganizationId};
use pib_service_facade::Service;

use crate::Result;

pub(crate) async fn handle<E: Into<pib_service_facade::Error> + Send + Sync>(
    State(service): State<Arc<dyn Service<E>>>,
    Extension(user): Extension<UserInfo>,
    Path((body_id, organization_id)): Path<(BodyId, OrganizationId)>,
    Json(payload): Json<RequestBody>,
) -> Result<Redirect>
where
    crate::Error: From<E>,
{
    service
        .handle_body_by_id_organization_by_id_patch(user, body_id, organization_id, payload)
        .await?;
    Ok(Redirect::to(&format!(
        "/body/{body_id}/organization/{organization_id}"
    )))
}

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

    use crate::Error;

    use super::{RequestBody, handle};
    use axum::{
        Extension, Json,
        extract::{Path, State},
    };
    use http::StatusCode;
    use mockall::predicate::eq;
    use pib_oparl_extensions::Color;
    use pib_service_api_auth::user::{Issuer, OidcSub, UserInfo};
    use pib_service_core_types::{BodyId, OrganizationId, UserId};
    use pib_service_facade::MockService;
    use pretty_assertions::{assert_eq, assert_matches};

    #[tokio::test]
    async fn valid() {
        let mut service = MockService::<pib_service_facade::Error>::new();

        let user_info = UserInfo {
            id: UserId::from_u128(0x5555),
            issuer: Issuer(String::from("http://auth.example.com")),
            sub: OidcSub("max.mustermann".to_string()),
            display_name: Some("Max Mustermann".to_string()),
            is_superuser: false,
        };

        let body_id = BodyId::from_u128(0x3333);
        let organization_id = OrganizationId::from_u128(0x3344);

        let payload = RequestBody {
            name: None,
            short_name: None,
            classification: None,
            start_date: None,
            end_date: None,
            website: Some(Some("https://gemeinderat.example.com".parse().unwrap())),
            color: Some(Some(Color {
                r: 0xaa,
                g: 0xbb,
                b: 0xcc,
            })),
        };

        service
            .expect_handle_body_by_id_organization_by_id_patch()
            .times(1)
            .with(
                eq(user_info),
                eq(body_id),
                eq(organization_id),
                eq(payload.clone()),
            )
            .return_once(|_, _, _, _| Ok(()));

        let response = handle(
            State(Arc::new(service)),
            Extension(UserInfo {
                id: UserId::from_u128(0x5555),
                issuer: Issuer("http://auth.example.com".to_string()),
                sub: OidcSub("max.mustermann".to_string()),
                display_name: Some("Max Mustermann".to_string()),
                is_superuser: false,
            }),
            Path((body_id, organization_id)),
            Json(payload),
        )
        .await
        .unwrap();
        assert_eq!(response.status_code(), StatusCode::SEE_OTHER);
        assert_eq!(
            response.location(),
            "/body/00000000-0000-0000-0000-000000003333/organization/00000000-0000-0000-0000-000000003344"
        );
    }

    #[tokio::test]
    async fn invalid() {
        let mut service = MockService::new();

        let user_info = UserInfo {
            id: UserId::from_u128(0x5555),
            issuer: Issuer(String::from("http://auth.example.com")),
            sub: OidcSub("max.mustermann".to_string()),
            display_name: Some("Max Mustermann".to_string()),
            is_superuser: false,
        };

        let body_id = BodyId::from_u128(0x3333);
        let organization_id = OrganizationId::from_u128(0x3344);

        let payload = RequestBody {
            name: None,
            short_name: None,
            classification: None,
            start_date: None,
            end_date: None,
            website: Some(Some("https://gemeinderat.example.com".parse().unwrap())),
            color: Some(Some(Color {
                r: 0xaa,
                g: 0xbb,
                b: 0xcc,
            })),
        };

        service
            .expect_handle_body_by_id_organization_by_id_patch()
            .times(1)
            .with(
                eq(user_info.clone()),
                eq(body_id),
                eq(organization_id),
                eq(payload.clone()),
            )
            .return_once(|_, _, _, _| Err(pib_service_facade::Error::NotFound));

        assert_matches!(
            handle(
                State(Arc::new(service)),
                Extension(user_info.clone()),
                Path((body_id, organization_id)),
                Json(payload)
            )
            .await,
            Err(Error::Service {
                source: pib_service_facade::Error::NotFound
            })
        );
    }
}
