use serde::{Deserialize, Serialize};
use solana_pubkey::Pubkey;

/// Subset of the Drift SpotMarket account fields needed by consumer services.
///
/// Includes fields for margin weight calculations, interest rate computation,
/// and oracle price lookups. Core fields (market_index, decimals, interest,
/// margin weights) are required; optional fields used only by specific
/// services use `#[serde(default)]` for flexibility.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SpotMarket {
    /// Raw pubkey bytes of the market account (used by api-v2 for lookups).
    #[serde(default)]
    pub pubkey: Vec<u8>,

    pub market_index: u16,

    // --- Margin weight fields ---
    pub initial_asset_weight: u32,

    pub initial_liability_weight: u32,

    pub imf_factor: u32,

    pub scale_initial_asset_weight_start: u64,

    // --- Token config ---
    pub decimals: u32,

    // --- Interest fields ---
    pub cumulative_deposit_interest: u128,

    pub cumulative_borrow_interest: u128,

    #[serde(default)]
    pub deposit_balance: u128,

    #[serde(default)]
    pub borrow_balance: u128,

    // --- Rate calculation fields (used by api-v2 yield service) ---
    #[serde(default)]
    pub optimal_utilization: u32,

    #[serde(default)]
    pub optimal_borrow_rate: u32,

    #[serde(default)]
    pub max_borrow_rate: u32,

    #[serde(default)]
    pub min_borrow_rate: u8,

    // --- Insurance fund (used by api-v2 yield service) ---
    #[serde(default)]
    pub insurance_fund: InsuranceFund,

    // --- Oracle ---
    #[serde(default)]
    pub historical_oracle_data: HistoricalOracleData,

    /// Oracle account pubkey (used by settlement-service for price lookups).
    #[serde(default)]
    pub oracle: Option<Pubkey>,
}

/// Subset of the Drift InsuranceFund struct.
///
/// Only `total_factor` is needed for deposit rate calculation.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct InsuranceFund {
    #[serde(default)]
    pub total_factor: u32,
}

/// Subset of the Drift HistoricalOracleData struct.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct HistoricalOracleData {
    #[serde(default)]
    pub last_oracle_price_twap5min: i64,
}

/// Drift user account containing spot positions.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct DriftUser {
    #[serde(default)]
    pub authority: Pubkey,
    pub spot_positions: Vec<SpotPosition>,
}

/// A single spot position within a Drift user account.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct SpotPosition {
    pub scaled_balance: u64,
    pub market_index: u16,

    pub balance_type: SpotBalanceType,

    #[serde(default)]
    pub open_orders: u8,

    #[serde(default)]
    pub open_bids: i64,

    #[serde(default)]
    pub open_asks: i64,

    #[serde(default)]
    pub cumulative_deposits: i64,
}

/// Whether a spot balance is a deposit or borrow.
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
pub enum SpotBalanceType {
    #[default]
    Deposit,
    Borrow,
}
