//! Wallet type - represents a project's credit account

use chrono::{DateTime, Utc};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

/// Wallet represents a project's credit account
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Wallet {
    /// Project ID (unique)
    pub project_id: String,
    /// Organization ID
    pub org_id: String,
    /// Current balance (in smallest credit unit)
    pub balance: i64,
    /// Reserved credits (pending reservations)
    pub reserved: i64,
    /// Total credits ever deposited
    pub total_deposited: i64,
    /// Total credits consumed
    pub total_consumed: i64,
    /// Wallet status
    pub status: WalletStatus,
    /// Creation timestamp
    pub created_at: DateTime<Utc>,
    /// Last update timestamp
    pub updated_at: DateTime<Utc>,
}

impl Wallet {
    /// Create a new wallet
    pub fn new(project_id: String, org_id: String, initial_balance: i64) -> Self {
        let now = Utc::now();
        Self {
            project_id,
            org_id,
            balance: initial_balance,
            reserved: 0,
            total_deposited: initial_balance,
            total_consumed: 0,
            status: WalletStatus::Active,
            created_at: now,
            updated_at: now,
        }
    }

    /// Get available balance (balance - reserved)
    pub fn available_balance(&self) -> i64 {
        self.balance - self.reserved
    }

    /// Check if wallet can afford an amount
    pub fn can_afford(&self, amount: i64) -> bool {
        self.available_balance() >= amount && self.status == WalletStatus::Active
    }

    /// Convert balance to decimal (assuming 2 decimal places)
    pub fn balance_as_decimal(&self) -> Decimal {
        Decimal::new(self.balance, 2)
    }
}

/// Wallet status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Default)]
pub enum WalletStatus {
    /// Wallet is active and can be used
    #[default]
    Active,
    /// Wallet is suspended (insufficient balance)
    Suspended,
    /// Wallet is closed
    Closed,
}


#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_wallet_creation() {
        let wallet = Wallet::new("proj-1".into(), "org-1".into(), 10000);
        assert_eq!(wallet.balance, 10000);
        assert_eq!(wallet.available_balance(), 10000);
        assert!(wallet.can_afford(5000));
    }

    #[test]
    fn test_available_balance() {
        let mut wallet = Wallet::new("proj-1".into(), "org-1".into(), 10000);
        wallet.reserved = 3000;
        assert_eq!(wallet.available_balance(), 7000);
        assert!(wallet.can_afford(7000));
        assert!(!wallet.can_afford(7001));
    }
}
