use serde::{Deserialize, Serialize};

#[cfg(feature = "ssr")]
use axum_session::SessionAnySession;

#[derive(Clone, Serialize, Deserialize)]
pub enum Alert {
    None,
    Info,
    Success,
    Warning,
    Error,
}

#[derive(Clone, Serialize)]
pub struct FlashMessage<S>
where
    S: Serialize,
{
    name: String,
    message: S,
    alert: Alert,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct Flash {
    name: String,
    message: String,
    alert: Alert,
}

impl Flash {
    pub fn message(&self) -> String {
        self.message.clone()
    }

    pub fn alert(&self) -> Alert {
        self.alert.clone()
    }
}

impl<S> FlashMessage<S>
where
    S: Serialize,
{
    pub fn new(name: &str, message: S) -> Self {
        Self {
            name: name.to_string(),
            message,
            alert: Alert::None,
        }
    }

    pub fn with_alert(mut self, alert: Alert) -> Self {
        self.alert = alert;
        self
    }
}

#[cfg(feature = "ssr")]
#[derive(Clone)]
pub struct FlashBag {
    session: SessionAnySession,
}

#[cfg(feature = "ssr")]
impl FlashBag {
    pub fn new(session: SessionAnySession) -> Self {
        Self { session }
    }

    pub fn set<T: Serialize>(&self, message: FlashMessage<T>) {
        let flash_name = &message.name;

        let name = format!("__flash_alert:{}__", flash_name);
        self.session.set(&name, message.alert);

        let name = format!("__flash:{}__", flash_name);
        self.session.set(&name, message.message);
    }

    pub fn get(&self, flash_name: &str) -> Option<Flash> {
        let name = format!("__flash:{}__", flash_name);

        let message = self.session.get(&name)?;

        let alert_name = format!("__flash_alert:{}__", flash_name);
        let alert = self.session.get(&alert_name).unwrap_or(Alert::None);

        self.clear(flash_name);

        Some(Flash {
            name,
            message,
            alert,
        })
    }

    pub fn clear(&self, name: &str) {
        let name = format!("__flash:{}__", name);
        let alert_name = format!("__flash_alert:{}__", name);
        self.session.remove(&name);
        self.session.remove(&alert_name);
    }
}
