// 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 oparl_types::Date;
use pib_service_core_types::{BodyId, Entity, MembershipId, OrganizationId, PersonId};
use serde::{Deserialize, Serialize};

use crate::Updatable;

pub mod get;
pub mod post;

pub mod by_id;

#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct Membership {
    pub person_id: PersonId,
    pub organization_id: OrganizationId,

    pub role: Option<String>,
    pub voting_right: Option<bool>,
    pub start_date: Option<Date>,
    pub end_date: Option<Date>,
    pub on_behalf_of: Option<OrganizationId>,
    pub keyword: Option<Vec<String>>,
    pub license: Option<String>,
    pub web: Option<String>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct MembershipParentId {
    pub body_id: BodyId,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct OrganizationMembershipParentId {
    pub body_id: BodyId,
    pub organization_id: OrganizationId,
}

impl From<OrganizationMembershipParentId> for MembershipParentId {
    fn from(
        OrganizationMembershipParentId {
            body_id,
            organization_id: _,
        }: OrganizationMembershipParentId,
    ) -> Self {
        Self { body_id }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct PersonMembershipParentId {
    pub body_id: BodyId,
    pub person_id: PersonId,
}

impl From<PersonMembershipParentId> for MembershipParentId {
    fn from(
        PersonMembershipParentId {
            body_id,
            person_id: _,
        }: PersonMembershipParentId,
    ) -> Self {
        Self { body_id }
    }
}

impl Entity<MembershipParentId, MembershipId> for Membership {}
impl Entity<OrganizationMembershipParentId, MembershipId> for Membership {}
impl Entity<PersonMembershipParentId, MembershipId> for Membership {}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UpdateMembership {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub role: Option<Option<String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub voting_right: Option<Option<bool>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub start_date: Option<Option<Date>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub end_date: Option<Option<Date>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub on_behalf_of: Option<Option<OrganizationId>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub keyword: Option<Option<Vec<String>>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub license: Option<Option<String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub web: Option<Option<String>>,
}

impl Updatable for Membership {
    type Update = UpdateMembership;

    fn build_update_from(
        &self,
        Self {
            person_id: _,
            organization_id: _,
            role,
            voting_right,
            start_date,
            end_date,
            on_behalf_of,
            keyword,
            license,
            web,
        }: &Self,
    ) -> Self::Update {
        let role = self.role.build_update_from(role);
        let voting_right = self.voting_right.build_update_from(voting_right);
        let start_date = self.start_date.build_update_from(start_date);
        let end_date = self.end_date.build_update_from(end_date);
        let on_behalf_of = self.on_behalf_of.build_update_from(on_behalf_of);
        let keyword = self.keyword.build_update_from(keyword);
        let license = self.license.build_update_from(license);
        let web = self.web.build_update_from(web);

        Self::Update {
            role,
            voting_right,
            start_date,
            end_date,
            on_behalf_of,
            keyword,
            license,
            web,
        }
    }
}
