// 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, Date, DateTime, EmailAddress, Name, OrganizationClassification, Url,
};
use pib_oparl_extensions::Color;
use pib_service_core_types::OrganizationId;

use crate::body::by_id::meeting::MeetingState;

pub trait Updatable {
    type Update;

    fn build_update_from(&self, old: &Self) -> Self::Update;
}

impl<T> Updatable for Option<T>
where
    T: Updatable<Update = Option<T>> + Clone + PartialEq,
{
    type Update = Option<Option<T>>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        if old == self {
            return None;
        }

        let Some(new) = self else {
            return None;
        };
        let Some(old) = old else {
            return Some(Some(new.clone()));
        };

        Some(new.build_update_from(old))
    }
}

impl<T: Clone + PartialEq> Updatable for Vec<T> {
    type Update = Option<Vec<T>>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for bool {
    type Update = Option<bool>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(*self)
    }
}

impl Updatable for u32 {
    type Update = Option<u32>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(*self)
    }
}

impl Updatable for Name {
    type Update = Option<Name>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for EmailAddress {
    type Update = Option<EmailAddress>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for BodyClassification {
    type Update = Option<BodyClassification>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for OrganizationClassification {
    type Update = Option<OrganizationClassification>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for Date {
    type Update = Option<Date>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for DateTime {
    type Update = Option<DateTime>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for Url {
    type Update = Option<Url>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for String {
    type Update = Option<String>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for MeetingState {
    type Update = Option<MeetingState>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(*self)
    }
}

impl Updatable for Color {
    type Update = Option<Color>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(self.clone())
    }
}

impl Updatable for OrganizationId {
    type Update = Option<OrganizationId>;

    fn build_update_from(&self, old: &Self) -> Self::Update {
        (old != self).then_some(*self)
    }
}
