use serde::{Serialize, Deserialize};
use tritools::time::unix_epoch_timestamp;
use super::id::Id;

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
pub enum ActionData {
    String(String),
    Int32(i32),
    Usize(usize),
    Many(Vec<ActionData>),
    #[default]
    Null,
}

impl ActionData {
    pub fn read_string(self) -> String {
        match self {
            ActionData::String(x) => x,
            _ => String::default(),
        }
    }

    pub fn read_int32(self) -> i32 {
        match self {
            ActionData::Int32(x) => x,
            _ => i32::default(),
        }
    }

    pub fn read_usize(self) -> usize {
        match self {
            ActionData::Usize(x) => x,
            _ => usize::default(),
        }
    }

    pub fn read_many(self) -> Vec<ActionData> {
        match self {
            ActionData::Many(x) => x,
            _ => Vec::default(),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum ActionType {
    /// A request to answer a question with a post.
    ///
    /// `questions` table.
    Answer,
    /// A request follow a private account.
    ///
    /// `users` table.
    Follow,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ActionRequest {
    pub id: Id,
    pub created: u128,
    pub owner: crate::model::id::Id,
    pub action_type: ActionType,
    /// The ID of the asset this request links to. Should exist in the correct
    /// table for the given [`ActionType`].
    pub linked_asset: Id,
    /// Optional data attached to the action request.
    pub data: ActionData,
}

impl ActionRequest {
    /// Create a new [`ActionRequest`].
    pub fn new(
        owner: crate::model::id::Id,
        action_type: ActionType,
        linked_asset: Id,
        data: Option<ActionData>,
    ) -> Self {
        Self {
            id: Id::new(),
            created: unix_epoch_timestamp(),
            owner,
            action_type,
            linked_asset,
            data: data.unwrap_or_default(),
        }
    }

    /// Create a new [`ActionRequest`] with the given `id`.
    pub fn with_id(
        id: Id,
        owner: crate::model::id::Id,
        action_type: ActionType,
        linked_asset: crate::model::id::Id,
        data: Option<ActionData>,
    ) -> Self {
        Self {
            id,
            created: unix_epoch_timestamp(),
            owner,
            action_type,
            linked_asset,
            data: data.unwrap_or_default(),
        }
    }
}
