use anchor_lang::{InstructionData, ToAccountMetas};
use solana_program::{instruction::Instruction, pubkey::Pubkey};

use crate::constants::{KAMINO_LENDING_PROGRAM_ID, KAMINO_REFERRER_USER_METADATA, RENT_SYSVAR_ID, SYSTEM_PROGRAM_ID};

pub struct InitKaminoParams {
    pub owner: Pubkey,
    pub payer: Pubkey,
    pub kamino_market: Pubkey,
}

pub fn init_kamino(params: &InitKaminoParams) -> Instruction {
    let vault = pyra_accounts::get_vault(&params.owner);
    let kamino_user_metadata = pyra_accounts::get_kamino_user_metadata(&params.owner);
    let kamino_obligation = pyra_accounts::get_kamino_obligation(&params.owner, &params.kamino_market);

    let accounts = crate::pyra_program::client::accounts::InitKamino {
        vault,
        payer: params.payer,
        kamino_program: KAMINO_LENDING_PROGRAM_ID,
        kamino_user_metadata,
        kamino_referrer_metadata: KAMINO_REFERRER_USER_METADATA,
        kamino_obligation,
        kamino_market: params.kamino_market,
        rent: RENT_SYSVAR_ID,
        system_program: SYSTEM_PROGRAM_ID,
    }
    .to_account_metas(None);

    let data = crate::pyra_program::client::args::InitKamino {}.data();

    Instruction {
        program_id: pyra_accounts::PYRA_PROGRAM_ID,
        accounts,
        data,
    }
}

#[cfg(test)]
#[allow(clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::unwrap_used, reason = "test code")]
mod tests {
    use super::*;
    use solana_pubkey::pubkey;

    #[test]
    fn test_init_kamino_instruction() {
        let owner = pubkey!("d4A2prbA2whesmvHaL88BH6Ewn5N4bTSjm4GiKy2eSi");
        let payer = pubkey!("7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF");
        let market = pubkey!("Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD");

        let ix = init_kamino(&InitKaminoParams {
            owner,
            payer,
            kamino_market: market,
        });

        assert_eq!(ix.program_id, pyra_accounts::PYRA_PROGRAM_ID);
        // Should have 9 accounts
        assert_eq!(ix.accounts.len(), 9);
        // vault is first and read-only (not writable in IDL)
        assert_eq!(ix.accounts[0].pubkey, pyra_accounts::get_vault(&owner));
        // payer is signer + writable
        assert_eq!(ix.accounts[1].pubkey, payer);
        assert!(ix.accounts[1].is_signer);
        assert!(ix.accounts[1].is_writable);
        // data should not be empty
        assert!(!ix.data.is_empty());
    }
}
