use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};

#[cfg(feature = "redis")]
use redis_derive::{FromRedisValue, ToRedisArgs};

/// Response for a successful login, containing the JWT.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AuthResponse {
    pub token: String,
}

/// Response after successfully sending a chat message.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct ChatSendMessageResponse {
    pub status: String,
    pub message: String,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct User {
    pub authority: String,
    pub username: String,
    pub profile_photo_url: Option<String>,
    pub discord_user: Option<DiscordUser>,
    pub updated_at: NaiveDateTime,
    pub risk_score: i64,
    pub is_banned: bool,
    pub role: Option<String>,
}

// Notifications

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "redis", derive(FromRedisValue, ToRedisArgs))]
pub struct ChatNotification {
    pub authority: String,
    pub username: String,
    pub text: String,
    pub id: u64,
    pub ts: i64,
    pub profile_photo_url: Option<String>,
    pub role: Option<String>,
    pub discord_user_id: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct ResetNotification {
    pub block_id: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Notification {
    Chat(ChatNotification),
    Reset(ResetNotification),
}

impl Notification {
    pub fn id(&self) -> String {
        match self {
            Notification::Chat(chat) => chat.id.to_string(),
            Notification::Reset(reset) => reset.block_id.to_string(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct DailyRevenue {
    pub day: String,
    pub revenue: i64,
}

// Username validation

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct UsernameValidationResponse {
    pub valid: bool,
    pub error: Option<String>,
}

impl UsernameValidationResponse {
    pub fn valid() -> Self {
        Self {
            valid: true,
            error: None,
        }
    }

    pub fn invalid(error: String) -> Self {
        Self {
            valid: false,
            error: Some(error),
        }
    }
}

/// Response for a successful Discord authentication.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DiscordAuthResponse {
    pub access_token: String,
}

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
pub struct DiscordUser {
    pub id: String,
    pub username: String,
    pub discriminator: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub global_name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub avatar: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub verified: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct OreBalance {
    pub wallet: u64,
    pub staked: u64,
    pub unrefined: u64,
    pub refined: u64,
    pub lifetime_deployed_sol: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct LeaderboardEntry {
    pub authority: String,
    pub amount: u64,
}
