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

use crate::constants::KAMINO_LENDING_PROGRAM_ID;

pub struct RefreshKaminoReserveParams {
    pub reserve: Pubkey,
    pub lending_market: Pubkey,
    pub pyth_oracle: Option<Pubkey>,
    pub switchboard_price_oracle: Option<Pubkey>,
    pub switchboard_twap_oracle: Option<Pubkey>,
    pub scope_prices: Option<Pubkey>,
}

pub fn refresh_kamino_reserve(params: &RefreshKaminoReserveParams) -> Instruction {
    let accounts = crate::kamino_lending_program::client::accounts::RefreshReserve {
        reserve: params.reserve,
        lending_market: params.lending_market,
        pyth_oracle: params.pyth_oracle,
        switchboard_price_oracle: params.switchboard_price_oracle,
        switchboard_twap_oracle: params.switchboard_twap_oracle,
        scope_prices: params.scope_prices,
    }
    .to_account_metas(None);

    let data = crate::kamino_lending_program::client::args::RefreshReserve {}.data();

    Instruction {
        program_id: KAMINO_LENDING_PROGRAM_ID,
        accounts,
        data,
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
    use super::*;
    use solana_pubkey::pubkey;

    #[test]
    fn test_refresh_reserve_all_oracles() {
        let reserve = pubkey!("d4A2prbA2whesmvHaL88BH6Ewn5N4bTSjm4GiKy2eSi");
        let lending_market = pubkey!("7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF");
        let pyth_oracle = pubkey!("Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD");
        let switchboard_price = pubkey!("AdtRGGhmqvom3Fk5H2LTnGMfcXmUQdhSz8aPJGfhFqHj");
        let switchboard_twap = pubkey!("DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5");
        let scope = pubkey!("3NJYftD5sjVfxFkKFgU7bbtBBhBsBYAg1CEhJkJ4iY3H");

        let ix = refresh_kamino_reserve(&RefreshKaminoReserveParams {
            reserve,
            lending_market,
            pyth_oracle: Some(pyth_oracle),
            switchboard_price_oracle: Some(switchboard_price),
            switchboard_twap_oracle: Some(switchboard_twap),
            scope_prices: Some(scope),
        });

        assert_eq!(ix.program_id, KAMINO_LENDING_PROGRAM_ID);
        // reserve is writable
        assert!(ix.accounts[0].is_writable);
        assert_eq!(ix.accounts[0].pubkey, reserve);
        // lending_market is read-only
        assert!(!ix.accounts[1].is_writable);
        assert_eq!(ix.accounts[1].pubkey, lending_market);
        // data should not be empty (contains discriminator)
        assert!(!ix.data.is_empty());
    }

    #[test]
    fn test_refresh_reserve_no_oracles() {
        let reserve = pubkey!("d4A2prbA2whesmvHaL88BH6Ewn5N4bTSjm4GiKy2eSi");
        let lending_market = pubkey!("7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF");

        let ix = refresh_kamino_reserve(&RefreshKaminoReserveParams {
            reserve,
            lending_market,
            pyth_oracle: None,
            switchboard_price_oracle: None,
            switchboard_twap_oracle: None,
            scope_prices: None,
        });

        assert_eq!(ix.program_id, KAMINO_LENDING_PROGRAM_ID);
        assert!(ix.accounts[0].is_writable);
        assert_eq!(ix.accounts[0].pubkey, reserve);
        assert!(!ix.data.is_empty());
    }
}
