use solana_sdk::{
    instruction::{AccountMeta, Instruction},
    pubkey::Pubkey,
    sysvar,
};

use crate::constants::Discriminator;
use crate::types::*;

/// Build a NominateAuthority instruction (discriminator 16).
///
/// Accounts (3): authority(signer), config(w), clock.
pub fn build_nominate_authority(
    authority: &Pubkey,
    config_pda: &Pubkey,
    params: &NominateAuthorityParams,
    program_id: &Pubkey,
) -> Instruction {
    let mut data = Vec::with_capacity(41);
    data.push(Discriminator::NominateAuthority as u8);
    data.extend_from_slice(params.new_authority.as_ref());
    data.extend_from_slice(&params.expiry_slot.to_le_bytes());

    let keys = vec![
        AccountMeta::new_readonly(*authority, true),
        AccountMeta::new(*config_pda, false),
        AccountMeta::new_readonly(sysvar::clock::id(), false),
    ];

    Instruction {
        program_id: *program_id,
        accounts: keys,
        data,
    }
}

/// Build an AcceptAuthority instruction (discriminator 17).
///
/// Accounts (3): newAuthority(signer), config(w), clock.
pub fn build_accept_authority(
    new_authority: &Pubkey,
    config_pda: &Pubkey,
    program_id: &Pubkey,
) -> Instruction {
    let data = vec![Discriminator::AcceptAuthority as u8];

    let keys = vec![
        AccountMeta::new_readonly(*new_authority, true),
        AccountMeta::new(*config_pda, false),
        AccountMeta::new_readonly(sysvar::clock::id(), false),
    ];

    Instruction {
        program_id: *program_id,
        accounts: keys,
        data,
    }
}

/// Build a SetQuotingAuthority instruction (discriminator 23).
///
/// Accounts (5+): authority(signer), config, midpriceOracle(w), curveMeta(w),
/// curveUpdates(w), [spreadConfig(w) optional].
pub fn build_set_quoting_authority(
    authority: &Pubkey,
    config_pda: &Pubkey,
    oracle_pda: &Pubkey,
    curve_meta_pda: &Pubkey,
    curve_updates_pda: &Pubkey,
    params: &SetQuotingAuthorityParams,
    program_id: &Pubkey,
) -> Instruction {
    let mut data = Vec::with_capacity(33);
    data.push(Discriminator::SetQuotingAuthority as u8);
    data.extend_from_slice(params.new_quoting_authority.as_ref());

    let mut keys = vec![
        AccountMeta::new_readonly(*authority, true),
        AccountMeta::new_readonly(*config_pda, false),
        AccountMeta::new(*oracle_pda, false),
        AccountMeta::new(*curve_meta_pda, false),
        AccountMeta::new(*curve_updates_pda, false),
    ];

    if let Some(spread_config_pda) = params.spread_config_pda {
        keys.push(AccountMeta::new(spread_config_pda, false));
    }

    Instruction {
        program_id: *program_id,
        accounts: keys,
        data,
    }
}
