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;

// ============================================================
// Reserve
// ============================================================

/// Kamino Reserve account — exact match of the on-chain IDL (padding omitted).
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoReserve {
    pub version: u64,
    pub last_update: KaminoLastUpdate,
    pub lending_market: Pubkey,
    pub farm_collateral: Pubkey,
    pub farm_debt: Pubkey,
    pub liquidity: KaminoReserveLiquidity,
    pub collateral: KaminoReserveCollateral,
    pub config: KaminoReserveConfig,
    pub borrowed_amount_outside_elevation_group: u64,
    pub borrowed_amounts_against_this_reserve_in_elevation_groups: [u64; 32],
    pub withdraw_queue: KaminoWithdrawQueue,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
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 market_price_sf: u128,
    pub market_price_last_updated_ts: u64,
    pub mint_decimals: u64,
    pub deposit_limit_crossed_timestamp: u64,
    pub borrow_limit_crossed_timestamp: u64,
    pub cumulative_borrow_rate_bsf: KaminoBigFractionBytes,
    pub accumulated_protocol_fees_sf: u128,
    pub accumulated_referrer_fees_sf: u128,
    pub pending_referrer_fees_sf: u128,
    pub absolute_referral_rate_sf: u128,
    pub token_program: Pubkey,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoReserveCollateral {
    pub mint_pubkey: Pubkey,
    pub mint_total_supply: u64,
    pub supply_vault: Pubkey,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoReserveConfig {
    pub status: u8,
    pub host_fixed_interest_rate_bps: u16,
    pub min_deleveraging_bonus_bps: u16,
    pub block_ctoken_usage: u8,
    pub protocol_order_execution_fee_pct: u8,
    pub protocol_take_rate_pct: u8,
    pub protocol_liquidation_fee_pct: u8,
    pub loan_to_value_pct: u8,
    pub liquidation_threshold_pct: u8,
    pub min_liquidation_bonus_bps: u16,
    pub max_liquidation_bonus_bps: u16,
    pub bad_debt_liquidation_bonus_bps: u16,
    pub deleveraging_margin_call_period_secs: u64,
    pub deleveraging_threshold_decrease_bps_per_day: u64,
    pub fees: KaminoReserveFees,
    pub borrow_rate_curve: KaminoBorrowRateCurve,
    pub borrow_factor_pct: u64,
    pub deposit_limit: u64,
    pub borrow_limit: u64,
    pub token_info: KaminoTokenInfo,
    pub deposit_withdrawal_cap: KaminoWithdrawalCaps,
    pub debt_withdrawal_cap: KaminoWithdrawalCaps,
    pub elevation_groups: [u8; 20],
    pub disable_usage_as_coll_outside_emode: u8,
    pub utilization_limit_block_borrowing_above_pct: u8,
    pub autodeleverage_enabled: u8,
    pub borrow_limit_outside_elevation_group: u64,
    pub borrow_limit_against_this_collateral_in_elevation_group: [u64; 32],
    pub deleveraging_bonus_increase_bps_per_day: u64,
    pub debt_maturity_timestamp: u64,
    pub debt_term_seconds: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoReserveFees {
    pub origination_fee_sf: u64,
    pub flash_loan_fee_sf: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoBorrowRateCurve {
    pub points: [KaminoCurvePoint; 11],
}

#[derive(Serialize, Deserialize, Clone, Debug, Default, Copy)]
pub struct KaminoCurvePoint {
    pub utilization_rate_bps: u32,
    pub borrow_rate_bps: u32,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoTokenInfo {
    pub name: String,
    pub heuristic: KaminoPriceHeuristic,
    pub max_twap_divergence_bps: u64,
    pub max_age_price_seconds: u64,
    pub max_age_twap_seconds: u64,
    pub scope_configuration: KaminoScopeConfiguration,
    pub switchboard_configuration: KaminoSwitchboardConfiguration,
    pub pyth_configuration: KaminoPythConfiguration,
    pub block_price_usage: u8,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoPriceHeuristic {
    pub lower: u64,
    pub upper: u64,
    pub exp: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoScopeConfiguration {
    pub price_feed: Pubkey,
    pub price_chain: [u16; 4],
    pub twap_chain: [u16; 4],
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoSwitchboardConfiguration {
    pub price_aggregator: Pubkey,
    pub twap_aggregator: Pubkey,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoPythConfiguration {
    pub price: Pubkey,
}

#[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,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoWithdrawQueue {
    pub queued_collateral_amount: u64,
    pub next_issued_ticket_sequence_number: u64,
    pub next_withdrawable_ticket_sequence_number: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoLastUpdate {
    pub slot: u64,
    pub stale: u8,
    pub price_status: u8,
}

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

// ============================================================
// Obligation
// ============================================================

/// Kamino Obligation account — exact match of the on-chain IDL (padding omitted).
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoObligation {
    pub tag: u64,
    pub last_update: KaminoLastUpdate,
    pub lending_market: Pubkey,
    pub owner: Pubkey,
    pub deposits: [KaminoObligationCollateral; 8],
    pub lowest_reserve_deposit_liquidation_ltv: u64,
    pub deposited_value_sf: u128,
    pub borrows: [KaminoObligationLiquidity; 5],
    pub borrow_factor_adjusted_debt_value_sf: u128,
    pub borrowed_assets_market_value_sf: u128,
    pub allowed_borrow_value_sf: u128,
    pub unhealthy_borrow_value_sf: u128,
    pub elevation_group: u8,
    pub num_of_obsolete_deposit_reserves: u8,
    pub has_debt: u8,
    pub referrer: Pubkey,
    pub borrowing_disabled: u8,
    pub autodeleverage_target_ltv_pct: u8,
    pub lowest_reserve_deposit_max_ltv_pct: u8,
    pub num_of_obsolete_borrow_reserves: u8,
    pub highest_borrow_factor_pct: u64,
    pub autodeleverage_margin_call_started_timestamp: u64,
    pub obligation_orders: [KaminoObligationOrder; 2],
    pub borrow_order: KaminoBorrowOrder,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoObligationCollateral {
    pub deposit_reserve: Pubkey,
    pub deposited_amount: u64,
    pub market_value_sf: u128,
    pub borrowed_amount_against_this_collateral_in_elevation_group: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoObligationLiquidity {
    pub borrow_reserve: Pubkey,
    pub cumulative_borrow_rate_bsf: KaminoBigFractionBytes,
    pub last_borrowed_at_timestamp: u64,
    pub borrowed_amount_sf: u128,
    pub market_value_sf: u128,
    pub borrow_factor_adjusted_market_value_sf: u128,
    pub borrowed_amount_outside_elevation_groups: u64,
    pub fixed_term_borrow_rollover_config: KaminoFixedTermBorrowRolloverConfig,
    pub borrowed_amount_at_expiration: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoObligationOrder {
    pub condition_threshold_sf: u128,
    pub opportunity_parameter_sf: u128,
    pub min_execution_bonus_bps: u16,
    pub max_execution_bonus_bps: u16,
    pub condition_type: u8,
    pub opportunity_type: u8,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoBorrowOrder {
    pub debt_liquidity_mint: Pubkey,
    pub remaining_debt_amount: u64,
    pub filled_debt_destination: Pubkey,
    pub min_debt_term_seconds: u64,
    pub fillable_until_timestamp: u64,
    pub placed_at_timestamp: u64,
    pub last_updated_at_timestamp: u64,
    pub requested_debt_amount: u64,
    pub max_borrow_rate_bps: u32,
    pub active: u8,
    pub enable_auto_rollover_on_filled_borrows: u8,
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct KaminoFixedTermBorrowRolloverConfig {
    pub auto_rollover_enabled: u8,
    pub open_term_allowed: u8,
    pub migration_to_fixed_enabled: u8,
    pub max_borrow_rate_bps: u32,
    pub min_debt_term_seconds: u64,
}

// ============================================================
// Withdraw Ticket
// ============================================================

#[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,
}

// ============================================================
// Elevation Group
// ============================================================

#[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,
}
