use crate::types::note::{PackNoteMaybeFull, Reaction};
use crate::types::user::PackUserBase;
use crate::types::Id;
use crate::{Packed, Required};
use chrono::{DateTime, Utc};
use magnetar_sdk_macros::pack;
use serde::{Deserialize, Serialize};
use strum::{EnumDiscriminants, EnumIter};
use ts_rs::TS;

#[derive(Clone, Debug, Deserialize, Serialize, TS)]
#[ts(export)]
pub struct NotificationBase {
    pub id: String,
    pub created_at: DateTime<Utc>,
    pub is_read: bool,
}

#[derive(Clone, Debug, Deserialize, Serialize, TS)]
#[ts(export)]
pub struct NotificationNoteExt {
    pub note: PackNoteMaybeFull,
}

#[derive(Clone, Debug, Deserialize, Serialize, TS)]
#[ts(export)]
pub struct NotificationUserExt {
    pub user: PackUserBase,
}

#[derive(Clone, Debug, Deserialize, Serialize, TS)]
#[ts(export)]
pub struct NotificationReactionExt {
    pub reaction: Reaction,
}

#[derive(Clone, Debug, Deserialize, Serialize, TS)]
#[ts(export)]
pub struct NotificationAppExt {
    pub body: String,
    pub header: String,
    pub icon: String,
}

pack!(PackNotificationFollow, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationUserExt> as follower);
pack!(PackNotificationFollowRequestReceived, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationUserExt> as follower);
pack!(PackNotificationFollowRequestAccepted, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationUserExt> as follower);
pack!(PackNotificationMention, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationNoteExt> as note);
pack!(PackNotificationReply, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationNoteExt> as note);
pack!(PackNotificationRenote, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationNoteExt> as note);
pack!(PackNotificationReaction, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationNoteExt> as note & Required<NotificationReactionExt> as reaction & Required<NotificationUserExt> as user);
pack!(PackNotificationQuote, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationNoteExt> as note);
pack!(PackNotificationPollEnd, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationNoteExt> as note);
pack!(PackNotificationApp, Required<Id> as id & Required<NotificationBase> as notification & Required<NotificationAppExt> as custom);

#[derive(Clone, Debug, Deserialize, Serialize, TS, EnumDiscriminants)]
#[strum_discriminants(name(NotificationType))]
#[strum_discriminants(ts(export))]
#[strum_discriminants(derive(Deserialize, Serialize, Hash, TS, EnumIter))]
#[ts(export)]
#[serde(tag = "type")]
pub enum PackNotification {
    Follow(PackNotificationFollow),
    FollowRequestReceived(PackNotificationFollowRequestReceived),
    FollowRequestAccepted(PackNotificationFollowRequestAccepted),
    Mention(PackNotificationMention),
    Reply(PackNotificationReply),
    Renote(PackNotificationRenote),
    Reaction(PackNotificationReaction),
    Quote(PackNotificationQuote),
    PollEnd(PackNotificationPollEnd),
    App(PackNotificationApp),
}
