use crate::i18n::i18n;
use glib::{Enum, Properties, prelude::*, subclass::prelude::*};
use serde::{Deserialize, Serialize};
use std::{cell::Cell, default::Default, fmt::Display};

mod imp {
    use super::*;

    #[derive(Default, Debug, Serialize, Deserialize, Properties)]
    #[properties(wrapper_type = super::FeedListSettings)]
    pub struct FeedListSettings {
        #[property(get, set, builder(GFeedOrder::Manual))]
        #[serde(default)]
        pub order: Cell<GFeedOrder>,

        #[property(get, set, name = "only-show-relevant", default_value = false)]
        #[serde(default)]
        pub only_show_relevant: Cell<bool>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for FeedListSettings {
        const NAME: &'static str = "FeedListSettings";
        type Type = super::FeedListSettings;
    }

    #[glib::derived_properties]
    impl ObjectImpl for FeedListSettings {}
}

glib::wrapper! {
    pub struct FeedListSettings(ObjectSubclass<imp::FeedListSettings>);
}

impl Serialize for FeedListSettings {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.imp().serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for FeedListSettings {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let inner = imp::FeedListSettings::deserialize(deserializer)?;
        Ok(inner.into())
    }
}

impl From<imp::FeedListSettings> for FeedListSettings {
    fn from(inner: imp::FeedListSettings) -> Self {
        glib::Object::builder()
            .property("only-show-relevant", inner.only_show_relevant.get())
            .property("order", inner.order.get())
            .build()
    }
}

impl Default for FeedListSettings {
    fn default() -> Self {
        imp::FeedListSettings::default().into()
    }
}

#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Enum)]
#[repr(u32)]
#[enum_type(name = "GFeedOrder")]
pub enum GFeedOrder {
    Alphabetical,
    #[default]
    Manual,
}

impl Display for GFeedOrder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            GFeedOrder::Alphabetical => write!(f, "{}", i18n("Alphabetical")),
            GFeedOrder::Manual => write!(f, "{}", i18n("Manual")),
        }
    }
}

impl From<u32> for GFeedOrder {
    fn from(value: u32) -> Self {
        match value {
            0 => Self::Alphabetical,
            1 => Self::Manual,
            _ => Self::Manual,
        }
    }
}

impl From<i32> for GFeedOrder {
    fn from(value: i32) -> Self {
        match value {
            0 => Self::Alphabetical,
            1 => Self::Manual,
            _ => Self::Manual,
        }
    }
}

impl From<GFeedOrder> for u32 {
    fn from(value: GFeedOrder) -> Self {
        match value {
            GFeedOrder::Alphabetical => 0,
            GFeedOrder::Manual => 1,
        }
    }
}

impl From<GFeedOrder> for i32 {
    fn from(value: GFeedOrder) -> Self {
        match value {
            GFeedOrder::Alphabetical => 0,
            GFeedOrder::Manual => 1,
        }
    }
}
