use solana_program::instruction::Instruction;
use solana_pubkey::Pubkey;

use crate::{
    initiate_withdraw,
    operations::{pay_fee_kamino, PayFeeKaminoParams},
    InitiateWithdrawParams,
};

pub struct WithdrawWithFeeKaminoParams {
    pub owner: Pubkey,
    /// Withdraw order account. Should be a freshly generated keypair. Must sign the transaction.
    pub withdraw_order: Pubkey,
    pub payer: Pubkey,
    pub destination: Pubkey,
    pub amount_base_units: u64,
    pub asset_id: pyra_tokens::AssetId,
    pub is_loan: bool,

    pub order_payer: Pubkey,
    /// Must sign the transaction in order to skip the time lock
    pub admin: Pubkey,
    pub fee_destination: Pubkey,
    pub liquidity_mint: Pubkey,
    pub liquidity_token_program: Pubkey,
    pub kamino_market: Pubkey,
    pub kamino_reserve: Pubkey,
    pub kamino_reserve_liquidity_supply: Pubkey,
    pub kamino_reserve_collateral_mint: Pubkey,
    pub kamino_reserve_collateral_supply: Pubkey,
    pub kamino_reserve_collateral_token_program: Pubkey,
    pub borrow_reserve_liquidity_fee_receiver: Pubkey,
    pub kamino_user_farm_state: Option<Pubkey>,
    pub kamino_reserve_farm_state: Option<Pubkey>,
}

pub fn withdraw_with_fee_kamino(params: &WithdrawWithFeeKaminoParams) -> Vec<Instruction> {
    let mut instructions = Vec::new();

    // First pay fee
    let pay_fee_params = PayFeeKaminoParams {
        owner: params.owner,
        withdraw_order: params.withdraw_order,
        payer: params.payer,
        destination: params.fee_destination,
        amount_base_units: params.amount_base_units,
        asset_id: params.asset_id,
        is_loan: params.is_loan,
        order_payer: params.order_payer,
        admin: params.admin,
        liquidity_mint: params.liquidity_mint,
        liquidity_token_program: params.liquidity_token_program,
        kamino_market: params.kamino_market,
        kamino_reserve: params.kamino_reserve,
        kamino_reserve_liquidity_supply: params.kamino_reserve_liquidity_supply,
        kamino_reserve_collateral_mint: params.kamino_reserve_collateral_mint,
        kamino_reserve_collateral_supply: params.kamino_reserve_collateral_supply,
        kamino_reserve_collateral_token_program: params.kamino_reserve_collateral_token_program,
        borrow_reserve_liquidity_fee_receiver: params.borrow_reserve_liquidity_fee_receiver,
        kamino_user_farm_state: params.kamino_user_farm_state,
        kamino_reserve_farm_state: params.kamino_reserve_farm_state,
    };
    let pay_fee_ix = pay_fee_kamino(&pay_fee_params);
    instructions.extend(pay_fee_ix);

    // Then initiate withdraw
    let initiate_withdraw_params = InitiateWithdrawParams {
        owner: params.owner,
        withdraw_order: params.withdraw_order,
        payer: params.payer,
        destination: params.destination,
        amount_base_units: params.amount_base_units,
        asset_id: params.asset_id,
        is_loan: params.is_loan,
        protocol_id: crate::pyra_program::types::ProtocolId::Kamino,
    };
    let initiate_withdraw_ix = initiate_withdraw(&initiate_withdraw_params);
    instructions.push(initiate_withdraw_ix);

    instructions
}
