// 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::{BodyClassification, DateTime, EmailAddress, Name, Url};
use pib_service_core_types::{BodyId, Entity};
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 Body {
    pub short_name: Option<Name>,
    pub name: Name,
    pub website: Option<Url>,
    pub license: Option<Url>,
    pub license_valid_since: Option<DateTime>,
    pub oparl_since: Option<DateTime>,
    pub ags: String,
    pub rgs: Option<String>,
    pub contact_email: Option<EmailAddress>,
    pub contact_name: Option<Name>,
    pub classification: Option<BodyClassification>,
    pub web: Option<Url>,
    pub is_public: bool,
}

impl Entity<(), BodyId> for Body {}

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

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

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

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

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

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

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

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

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

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

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

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

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

impl Updatable for Body {
    type Update = UpdateBody;

    fn build_update_from(
        &self,
        Self {
            short_name,
            name,
            website,
            license,
            license_valid_since,
            oparl_since,
            ags,
            rgs,
            contact_email,
            contact_name,
            classification,
            web,
            is_public,
        }: &Self,
    ) -> Self::Update {
        let short_name = self.short_name.build_update_from(short_name);
        let name = self.name.build_update_from(name);
        let website = self.website.build_update_from(website);
        let license = self.license.build_update_from(license);
        let license_valid_since = self
            .license_valid_since
            .build_update_from(license_valid_since);
        let oparl_since = self.oparl_since.build_update_from(oparl_since);
        let ags = self.ags.build_update_from(ags);
        let rgs = self.rgs.build_update_from(rgs);
        let contact_email = self.contact_email.build_update_from(contact_email);
        let contact_name = self.contact_name.build_update_from(contact_name);
        let classification = self.classification.build_update_from(classification);
        let web = self.web.build_update_from(web);
        let is_public = self.is_public.build_update_from(is_public);

        Self::Update {
            short_name,
            name,
            website,
            license,
            license_valid_since,
            oparl_since,
            ags,
            rgs,
            contact_email,
            contact_name,
            classification,
            web,
            is_public,
        }
    }
}
