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

use crate::{
    fulfill_borrow_kamino, fulfill_withdraw_kamino, initiate_withdraw, FulfillBorrowKaminoParams,
    FulfillWithdrawKaminoParams, InitiateWithdrawParams,
};

pub struct PayFeeKaminoParams {
    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 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 pay_fee_kamino(params: &PayFeeKaminoParams) -> Vec<Instruction> {
    let mut instructions = Vec::new();

    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: false,
        protocol_id: crate::pyra_program::types::ProtocolId::Kamino,
    };
    let initiate_withdraw_ix = initiate_withdraw(&initiate_withdraw_params);
    instructions.push(initiate_withdraw_ix);

    let fulfill_ix = if params.is_loan {
        let fulfill_borrow_params = FulfillBorrowKaminoParams {
            amount_base_units: params.amount_base_units,
            withdraw_order: params.withdraw_order,
            owner: params.owner,
            order_payer: params.payer,
            admin: params.admin,
            // Pay-fee runs the fulfill in the same tx as the initiate, so admin must
            // sign to skip the time lock.
            admin_is_signer: true,
            payer: params.payer,
            destination: params.destination,
            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,
            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,
        };
        fulfill_borrow_kamino(&fulfill_borrow_params)
    } else {
        let fulfill_withdraw_params = FulfillWithdrawKaminoParams {
            amount_base_units: params.amount_base_units,
            withdraw_order: params.withdraw_order,
            owner: params.owner,
            order_payer: params.payer,
            admin: params.admin,
            // Pay-fee runs the fulfill in the same tx as the initiate, so admin must
            // sign to skip the time lock.
            admin_is_signer: true,
            payer: params.payer,
            destination: params.destination,
            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,
            kamino_user_farm_state: params.kamino_user_farm_state,
            kamino_reserve_farm_state: params.kamino_reserve_farm_state,
        };
        fulfill_withdraw_kamino(&fulfill_withdraw_params)
    };

    instructions.push(fulfill_ix);

    instructions
}
