// 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_types::Pagination;
use pib_service_core_types::{AgendaItemId, BodyId, MeetingId, OrganizationId, PersonId};

mod requests {
    pub(super) use pib_client_requests::{
        body::{
            self,
            by_id::{
                meeting::{self, by_id::agenda_item},
                organization, person,
            },
        },
        config, get, me,
    };
}
mod types {
    pub(super) use pib_service_api_types::{
        body::{
            self,
            by_id::{
                meeting::{self, by_id::agenda_item},
                organization, person,
            },
        },
        config, get, me,
    };
}

#[async_trait::async_trait(?Send)]
pub trait PibClient: Clone {
    type ClientError: std::error::Error;

    async fn get(&self) -> Result<types::get::ResponseBody, Self::ClientError>;

    async fn config_get(&self) -> Result<types::config::get::ResponseBody, Self::ClientError>;

    async fn body_get(
        &self,
        pagination: Pagination,
    ) -> Result<types::body::get::ResponseBody, Self::ClientError>;

    async fn body_post(
        &self,
        payload: types::body::post::RequestBody,
    ) -> Result<types::body::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_get(
        &self,
        body_id: BodyId,
    ) -> Result<types::body::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_meeting_get(
        &self,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::meeting::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_meeting_post(
        &self,
        body_id: BodyId,
        payload: types::meeting::post::RequestBody,
    ) -> Result<types::meeting::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_meeting_by_id_get(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
    ) -> Result<types::meeting::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_meeting_by_id_agenda_item_get(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
        pagination: Pagination,
    ) -> Result<types::agenda_item::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_meeting_by_id_agenda_item_post(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
        payload: types::meeting::by_id::agenda_item::post::RequestBody,
    ) -> Result<types::agenda_item::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_meeting_by_id_agenda_item_by_id_get(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
        agenda_item_id: AgendaItemId,
    ) -> Result<types::agenda_item::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_organization_get(
        &self,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::organization::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_organization_post(
        &self,
        body_id: BodyId,
        payload: types::organization::post::RequestBody,
    ) -> Result<types::organization::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_organization_by_id_get(
        &self,
        body_id: BodyId,
        organization_id: OrganizationId,
    ) -> Result<types::organization::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_person_get(
        &self,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::person::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_person_post(
        &self,
        body_id: BodyId,
        payload: types::person::post::RequestBody,
    ) -> Result<types::person::by_id::get::ResponseBody, Self::ClientError>;

    async fn body_by_id_person_by_id_get(
        &self,
        body_id: BodyId,
        person_id: PersonId,
    ) -> Result<types::person::by_id::get::ResponseBody, Self::ClientError>;

    async fn me_profile_get(
        &self,
    ) -> Result<types::me::profile::get::ResponseBody, Self::ClientError>;

    async fn me_profile_patch(
        &self,
        payload: types::me::profile::patch::RequestBody,
    ) -> Result<types::me::profile::get::ResponseBody, Self::ClientError>;
}

#[async_trait::async_trait(?Send)]
impl<C: http_request_derive_client::Client + Clone> PibClient for C {
    type ClientError = C::ClientError;

    async fn get(&self) -> Result<types::get::ResponseBody, Self::ClientError> {
        let response = self.execute(requests::get::Request).await?;
        Ok(response.0)
    }

    async fn config_get(&self) -> Result<types::config::get::ResponseBody, Self::ClientError> {
        let response = self.execute(requests::config::get::Request).await?;
        Ok(response.0)
    }

    async fn body_get(
        &self,
        pagination: Pagination,
    ) -> Result<types::body::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::body::get::Request { pagination })
            .await?;
        Ok(response.0)
    }

    async fn body_post(
        &self,
        payload: types::body::post::RequestBody,
    ) -> Result<types::body::by_id::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::body::post::Request { payload })
            .await?
            .0)
    }

    async fn body_by_id_get(
        &self,
        body_id: BodyId,
    ) -> Result<types::body::by_id::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::body::by_id::get::Request { body_id })
            .await?;
        Ok(response.0)
    }

    async fn body_by_id_meeting_get(
        &self,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::meeting::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::meeting::get::Request {
                body_id,
                pagination,
            })
            .await?
            .0)
    }

    async fn body_by_id_meeting_post(
        &self,
        body_id: BodyId,
        payload: types::meeting::post::RequestBody,
    ) -> Result<types::meeting::by_id::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::meeting::post::Request { body_id, payload })
            .await?
            .0)
    }

    async fn body_by_id_meeting_by_id_get(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
    ) -> Result<types::meeting::by_id::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::meeting::by_id::get::Request {
                body_id,
                meeting_id,
            })
            .await?;
        Ok(response.0)
    }

    async fn body_by_id_meeting_by_id_agenda_item_get(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
        pagination: Pagination,
    ) -> Result<types::agenda_item::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::agenda_item::get::Request {
                body_id,
                meeting_id,
                pagination,
            })
            .await?;
        Ok(response.0)
    }

    async fn body_by_id_meeting_by_id_agenda_item_post(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
        payload: types::agenda_item::post::RequestBody,
    ) -> Result<types::agenda_item::by_id::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::agenda_item::post::Request {
                body_id,
                meeting_id,
                payload,
            })
            .await?
            .0)
    }

    async fn body_by_id_meeting_by_id_agenda_item_by_id_get(
        &self,
        body_id: BodyId,
        meeting_id: MeetingId,
        agenda_item_id: AgendaItemId,
    ) -> Result<types::agenda_item::by_id::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::agenda_item::by_id::get::Request {
                body_id,
                meeting_id,
                agenda_item_id,
            })
            .await?;
        Ok(response.0)
    }

    async fn body_by_id_organization_get(
        &self,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::organization::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::organization::get::Request {
                body_id,
                pagination,
            })
            .await?
            .0)
    }

    async fn body_by_id_organization_post(
        &self,
        body_id: BodyId,
        payload: types::organization::post::RequestBody,
    ) -> Result<types::organization::by_id::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::organization::post::Request { body_id, payload })
            .await?
            .0)
    }

    async fn body_by_id_organization_by_id_get(
        &self,
        body_id: BodyId,
        organization_id: OrganizationId,
    ) -> Result<types::organization::by_id::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::organization::by_id::get::Request {
                body_id,
                organization_id,
            })
            .await?;
        Ok(response.0)
    }

    async fn body_by_id_person_get(
        &self,
        body_id: BodyId,
        pagination: Pagination,
    ) -> Result<types::person::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::person::get::Request {
                body_id,
                pagination,
            })
            .await?
            .0)
    }

    async fn body_by_id_person_post(
        &self,
        body_id: BodyId,
        payload: types::person::post::RequestBody,
    ) -> Result<types::person::by_id::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::person::post::Request { body_id, payload })
            .await?
            .0)
    }

    async fn body_by_id_person_by_id_get(
        &self,
        body_id: BodyId,
        person_id: PersonId,
    ) -> Result<types::person::by_id::get::ResponseBody, Self::ClientError> {
        let response = self
            .execute(requests::person::by_id::get::Request { body_id, person_id })
            .await?;
        Ok(response.0)
    }

    async fn me_profile_get(
        &self,
    ) -> Result<types::me::profile::get::ResponseBody, Self::ClientError> {
        Ok(self.execute(requests::me::profile::get::Request).await?.0)
    }

    async fn me_profile_patch(
        &self,
        payload: types::me::profile::patch::RequestBody,
    ) -> Result<types::me::profile::get::ResponseBody, Self::ClientError> {
        Ok(self
            .execute(requests::me::profile::patch::Request { payload })
            .await?
            .0)
    }
}
