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

/// Kamino Fraction scale factor: U68F60 = 2^60.
///
/// All `_sf` fields in Kamino types are scaled by this value.
pub const KAMINO_FRACTION_SCALE: u128 = 1 << 60;

/// Subset of the Kamino Reserve account fields needed by consumer services.
///
/// Equivalent to `SpotMarket` for Drift. Includes fields for collateral
/// valuation, interest rate computation, and liquidity tracking.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct KaminoReserve {
    pub lending_market: Pubkey,
    pub liquidity: KaminoReserveLiquidity,
    pub collateral: KaminoReserveCollateral,
    pub config: KaminoReserveConfig,
    pub last_update: KaminoLastUpdate,
}

/// Subset of Reserve.liquidity fields.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct KaminoReserveLiquidity {
    pub mint_pubkey: Pubkey,
    pub supply_vault: Pubkey,
    pub fee_vault: Pubkey,
    pub total_available_amount: u64,
    pub borrowed_amount_sf: u128,
    pub cumulative_borrow_rate_bsf: KaminoBigFractionBytes,
    #[serde(default)]
    pub accumulated_protocol_fees_sf: u128,
    #[serde(default)]
    pub accumulated_referrer_fees_sf: u128,
    #[serde(default)]
    pub pending_referrer_fees_sf: u128,
    pub mint_decimals: u64,
    pub market_price_sf: u128,
    /// Token program (SPL Token or Token-2022) for this reserve's mint.
    #[serde(default)]
    pub token_program: Pubkey,
}

/// Subset of Reserve.collateral fields.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct KaminoReserveCollateral {
    pub mint_pubkey: Pubkey,
    pub supply_vault: Pubkey,
    pub mint_total_supply: u64,
}

/// Subset of Reserve.config fields.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct KaminoReserveConfig {
    pub loan_to_value_pct: u8,
    pub liquidation_threshold_pct: u8,
    pub protocol_take_rate_pct: u8,
    pub protocol_liquidation_fee_pct: u8,
    pub borrow_factor_pct: u64,
    pub deposit_limit: u64,
    pub borrow_limit: u64,
    pub fees: KaminoReserveFees,
    pub borrow_rate_curve: KaminoBorrowRateCurve,
    pub deposit_withdrawal_cap: KaminoWithdrawalCaps,
    pub debt_withdrawal_cap: KaminoWithdrawalCaps,
    pub elevation_groups: [u8; 20],
    #[serde(default)]
    pub token_info: KaminoTokenInfo,
}

/// Oracle and price-validation configuration for a reserve's token.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoTokenInfo {
    /// Human-readable token name (UTF-8, up to 32 bytes on-chain).
    #[serde(default)]
    pub name: String,
    #[serde(default)]
    pub heuristic: KaminoPriceHeuristic,
    #[serde(default)]
    pub max_twap_divergence_bps: u64,
    #[serde(default)]
    pub max_age_price_seconds: u64,
    #[serde(default)]
    pub max_age_twap_seconds: u64,
    #[serde(default)]
    pub scope_configuration: KaminoScopeConfiguration,
    #[serde(default)]
    pub switchboard_configuration: KaminoSwitchboardConfiguration,
    #[serde(default)]
    pub pyth_configuration: KaminoPythConfiguration,
    #[serde(default)]
    pub block_price_usage: u8,
}

/// Price heuristic bounds for sanity-checking oracle prices.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoPriceHeuristic {
    pub lower: u64,
    pub upper: u64,
    pub exp: u64,
}

/// Scope oracle configuration.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoScopeConfiguration {
    #[serde(default)]
    pub price_feed: Pubkey,
    #[serde(default)]
    pub price_chain: [u16; 4],
    #[serde(default)]
    pub twap_chain: [u16; 4],
}

/// Switchboard oracle configuration.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoSwitchboardConfiguration {
    #[serde(default)]
    pub price_aggregator: Pubkey,
    #[serde(default)]
    pub twap_aggregator: Pubkey,
}

/// Pyth oracle configuration.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoPythConfiguration {
    #[serde(default)]
    pub price: Pubkey,
}

/// Kamino obligation account, equivalent to `DriftUser`.
///
/// Tracks a user's deposits and borrows within a Kamino lending market.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct KaminoObligation {
    pub lending_market: Pubkey,
    #[serde(default)]
    pub owner: Pubkey,
    pub deposits: Vec<KaminoObligationCollateral>,
    pub borrows: Vec<KaminoObligationLiquidity>,
    pub deposited_value_sf: u128,
    pub borrowed_assets_market_value_sf: u128,
    pub allowed_borrow_value_sf: u128,
    pub unhealthy_borrow_value_sf: u128,
    pub has_debt: u8,
    pub elevation_group: u8,
    pub last_update: KaminoLastUpdate,
}

/// Obligation deposit position, equivalent to `SpotPosition` (deposit side).
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoObligationCollateral {
    pub deposit_reserve: Pubkey,
    pub deposited_amount: u64,
    pub market_value_sf: u128,
}

/// Obligation borrow position, equivalent to `SpotPosition` (borrow side).
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoObligationLiquidity {
    pub borrow_reserve: Pubkey,
    pub cumulative_borrow_rate_bsf: KaminoBigFractionBytes,
    pub borrowed_amount_sf: u128,
    pub market_value_sf: u128,
    pub borrow_factor_adjusted_market_value_sf: u128,
}

/// Kamino withdraw ticket for queued withdrawal flow.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct KaminoWithdrawTicket {
    pub sequence_number: u64,
    pub owner: Pubkey,
    pub reserve: Pubkey,
    pub user_destination_liquidity_ta: Pubkey,
    pub queued_collateral_amount: u64,
    pub created_at_timestamp: u64,
    pub invalid: u8,
}

/// Kamino elevation group for xStocks and isolated markets.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoElevationGroup {
    pub max_liquidation_bonus_bps: u16,
    pub id: u8,
    pub ltv_pct: u8,
    pub liquidation_threshold_pct: u8,
    pub allow_new_loans: u8,
    pub max_reserves_as_collateral: u8,
    pub debt_reserve: Pubkey,
}

/// Slot-based staleness tracker.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoLastUpdate {
    pub slot: u64,
    pub stale: u8,
}

/// 256-bit fixed-point number stored as four u64 limbs.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoBigFractionBytes {
    pub value: [u64; 4],
}

/// Reserve fee configuration.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoReserveFees {
    #[serde(default)]
    pub origination_fee_sf: u64,
    #[serde(default)]
    pub flash_loan_fee_sf: u64,
}

/// Piecewise-linear borrow rate curve with up to 11 points.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoBorrowRateCurve {
    pub points: [KaminoCurvePoint; 11],
}

/// Single point on the borrow rate curve.
#[derive(Serialize, Deserialize, Clone, Debug, Default, Copy)]
pub struct KaminoCurvePoint {
    pub utilization_rate_bps: u32,
    pub borrow_rate_bps: u32,
}

/// Withdrawal/debt capacity limiter with time-based resets.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoWithdrawalCaps {
    pub config_capacity: i64,
    pub current_total: i64,
    pub last_interval_start_timestamp: u64,
    pub config_interval_length_seconds: u64,
}
