// 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 crate::{Error, Result, traits::ForInventory as _};
use pib_service_api_auth::user::UserInfo;
use pib_service_api_permissions::Permissions;
use pib_service_api_types::{
    self as types,
    config::{oidc::OidcConfig, oparl::OParlConfig},
};
use pib_service_core_types::{
    AgendaItemId, BodyId, BodyPermissionId, MeetingId, OrganizationId, PersonId, UserId,
};
use pib_service_facade::{Service, paging::Pagination};
use pib_service_inventory::InventoryProvider;

#[derive(Debug, Clone)]
pub struct Backend {
    pub(crate) inventory_provider: Arc<dyn InventoryProvider>,
    pub(crate) permissions: Arc<dyn Permissions>,
    pub(crate) oidc: OidcConfig,
    pub(crate) oparl: Option<OParlConfig>,
}

impl Backend {
    pub fn new(
        inventory_provider: Arc<dyn InventoryProvider>,
        permissions: Arc<dyn Permissions>,
        oidc: OidcConfig,
        oparl: Option<OParlConfig>,
    ) -> Self {
        Self {
            inventory_provider,
            permissions,
            oidc,
            oparl,
        }
    }
}

#[async_trait::async_trait]
impl Service<Error> for Backend {
    async fn handle_get(&self) -> Result<types::get::ResponseBody> {
        self.get().await
    }

    async fn handle_config_get(&self) -> Result<types::config::get::ResponseBody> {
        self.config_get().await
    }

    async fn handle_profile_me_get(
        &self,
        user: UserInfo,
    ) -> Result<types::me::profile::get::ResponseBody> {
        self.profile_me_get(user).await
    }

    async fn handle_profile_me_patch(
        &self,
        user: UserInfo,
        payload: types::me::profile::patch::RequestBody,
    ) -> Result<()> {
        self.profile_me_patch(user, payload).await
    }

    async fn handle_user_get(
        &self,
        user: UserInfo,
        pagination: Pagination,
    ) -> Result<types::user::get::ResponseBody> {
        self.user_get(user, pagination.for_inventory()).await
    }

    async fn handle_user_by_id_get(
        &self,
        user: UserInfo,
        user_id: UserId,
    ) -> Result<types::user::by_id::get::ResponseBody> {
        self.user_by_id_get(user, user_id).await
    }

    async fn handle_body_get(
        &self,
        user: UserInfo,
        pagination: Pagination,
    ) -> Result<types::body::get::ResponseBody> {
        self.body_get(user, pagination.for_inventory()).await
    }

    async fn handle_body_post(
        &self,
        user: UserInfo,
        payload: types::body::post::RequestBody,
    ) -> Result<BodyId> {
        self.body_post(user, payload).await
    }

    async fn handle_body_by_id_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
    ) -> Result<types::body::by_id::get::ResponseBody> {
        self.body_by_id_get(user, body_id).await
    }

    async fn handle_body_by_id_patch(
        &self,
        user: UserInfo,
        body_id: BodyId,
        payload: types::body::by_id::patch::RequestBody,
    ) -> Result<()> {
        self.body_by_id_patch(user, body_id, payload).await
    }

    async fn handle_body_by_id_permission_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::body::by_id::permission::get::ResponseBody> {
        self.body_by_id_permission_get(user, body_id, pagination.for_inventory())
            .await
    }

    async fn handle_body_by_id_permission_post(
        &self,
        user: UserInfo,
        body_id: BodyId,
        payload: types::body::by_id::permission::post::RequestBody,
    ) -> Result<BodyPermissionId> {
        self.body_by_id_permission_post(user, body_id, payload)
            .await
    }

    async fn handle_body_by_id_permission_by_id_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        permission_id: BodyPermissionId,
    ) -> Result<types::body::by_id::permission::by_id::get::ResponseBody> {
        self.body_by_id_permission_by_id_get(user, body_id, permission_id)
            .await
    }

    async fn handle_body_by_id_person_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::body::by_id::person::get::ResponseBody> {
        self.body_by_id_person_get(user, body_id, pagination.for_inventory())
            .await
    }

    async fn handle_body_by_id_person_post(
        &self,
        user: UserInfo,
        body_id: BodyId,
        payload: types::body::by_id::person::post::RequestBody,
    ) -> Result<PersonId> {
        self.body_by_id_person_post(user, body_id, payload).await
    }

    async fn handle_body_by_id_person_by_id_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        person_id: PersonId,
    ) -> Result<types::body::by_id::person::by_id::get::ResponseBody> {
        self.body_by_id_person_by_id_get(user, body_id, person_id)
            .await
    }

    async fn handle_body_by_id_person_by_id_patch(
        &self,
        user: UserInfo,
        body_id: BodyId,
        person_id: PersonId,
        payload: types::body::by_id::person::by_id::patch::RequestBody,
    ) -> Result<()> {
        self.body_by_id_person_by_id_patch(user, body_id, person_id, payload)
            .await
    }

    async fn handle_body_by_id_organization_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::body::by_id::organization::get::ResponseBody> {
        self.body_by_id_organization_get(user, body_id, pagination.for_inventory())
            .await
    }

    async fn handle_body_by_id_organization_post(
        &self,
        user: UserInfo,
        body_id: BodyId,
        payload: types::body::by_id::organization::post::RequestBody,
    ) -> Result<OrganizationId> {
        self.body_by_id_organization_post(user, body_id, payload)
            .await
    }

    async fn handle_body_by_id_organization_by_id_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        organization_id: OrganizationId,
    ) -> Result<types::body::by_id::organization::by_id::get::ResponseBody> {
        self.body_by_id_organization_by_id_get(user, body_id, organization_id)
            .await
    }

    async fn handle_body_by_id_organization_by_id_patch(
        &self,
        user: UserInfo,
        body_id: BodyId,
        organization_id: OrganizationId,
        payload: types::body::by_id::organization::by_id::patch::RequestBody,
    ) -> Result<()> {
        self.body_by_id_organization_by_id_patch(user, body_id, organization_id, payload)
            .await
    }

    async fn handle_body_by_id_meeting_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::body::by_id::meeting::get::ResponseBody> {
        self.body_by_id_meeting_get(user, body_id, pagination.for_inventory())
            .await
    }

    async fn handle_body_by_id_meeting_post(
        &self,
        user: UserInfo,
        body_id: BodyId,
        payload: types::body::by_id::meeting::post::RequestBody,
    ) -> Result<MeetingId> {
        self.body_by_id_meeting_post(user, body_id, payload).await
    }

    async fn handle_body_by_id_meeting_by_id_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        meeting_id: MeetingId,
    ) -> Result<types::body::by_id::meeting::by_id::get::ResponseBody> {
        self.body_by_id_meeting_by_id_get(user, body_id, meeting_id)
            .await
    }

    async fn handle_body_by_id_meeting_by_id_patch(
        &self,
        user: UserInfo,
        body_id: BodyId,
        meeting_id: MeetingId,
        payload: types::body::by_id::meeting::by_id::patch::RequestBody,
    ) -> Result<()> {
        self.body_by_id_meeting_by_id_patch(user, body_id, meeting_id, payload)
            .await
    }

    async fn handle_body_by_id_meeting_by_id_agenda_item_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        meeting_id: MeetingId,
        pagination: Pagination,
    ) -> Result<types::body::by_id::meeting::by_id::agenda_item::get::ResponseBody> {
        self.body_by_id_meeting_by_id_agenda_item_get(
            user,
            body_id,
            meeting_id,
            pagination.for_inventory(),
        )
        .await
    }

    async fn handle_body_by_id_meeting_by_id_agenda_item_post(
        &self,
        user: UserInfo,
        body_id: BodyId,
        meeting_id: MeetingId,
        payload: types::body::by_id::meeting::by_id::agenda_item::post::RequestBody,
    ) -> Result<AgendaItemId> {
        self.body_by_id_meeting_by_id_agenda_item_post(user, body_id, meeting_id, payload)
            .await
    }

    async fn handle_body_by_id_meeting_by_id_agenda_item_by_id_get(
        &self,
        user: UserInfo,
        body_id: BodyId,
        meeting_id: MeetingId,
        agenda_item_id: AgendaItemId,
    ) -> Result<types::body::by_id::meeting::by_id::agenda_item::by_id::get::ResponseBody> {
        self.body_by_id_meeting_by_id_agenda_item_by_id_get(
            user,
            body_id,
            meeting_id,
            agenda_item_id,
        )
        .await
    }

    async fn handle_body_by_id_meeting_by_id_agenda_item_by_id_patch(
        &self,
        user: UserInfo,
        body_id: BodyId,
        meeting_id: MeetingId,
        agenda_item_id: AgendaItemId,
        payload: types::body::by_id::meeting::by_id::agenda_item::by_id::patch::RequestBody,
    ) -> Result<()> {
        self.body_by_id_meeting_by_id_agenda_item_by_id_patch(
            user,
            body_id,
            meeting_id,
            agenda_item_id,
            payload,
        )
        .await
    }
}
