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

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

/// Build an UpdateMidprice instruction (discriminator 5).
///
/// Accounts (3): authority(signer), midpriceOracle(w), clock.
pub fn build_update_midprice(
    authority: &Pubkey,
    midprice_oracle_pda: &Pubkey,
    params: &UpdateMidpriceParams,
    program_id: &Pubkey,
) -> Instruction {
    let sequence = params.sequence.unwrap_or(0);

    let mut data = Vec::with_capacity(17);
    data.push(Discriminator::UpdateMidprice as u8);
    data.extend_from_slice(&sequence.to_le_bytes());
    data.extend_from_slice(&params.midprice_q32.to_le_bytes());

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

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

/// Build an UpdateBaseSpread instruction (discriminator 9).
///
/// Accounts (3): authority(signer), midpriceOracle(w), clock.
pub fn build_update_base_spread(
    authority: &Pubkey,
    midprice_oracle_pda: &Pubkey,
    params: &UpdateBaseSpreadParams,
    program_id: &Pubkey,
) -> Instruction {
    let sequence = params.sequence.unwrap_or(0);

    let mut data = Vec::with_capacity(17);
    data.push(Discriminator::UpdateBaseSpread as u8);
    data.extend_from_slice(&sequence.to_le_bytes());
    data.extend_from_slice(&params.spread_factor_q32.to_le_bytes());

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

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

/// Build an UpdateMidpriceAndBaseSpread instruction (discriminator 10).
///
/// Accounts (3): authority(signer), midpriceOracle(w), clock.
pub fn build_update_midprice_and_base_spread(
    authority: &Pubkey,
    midprice_oracle_pda: &Pubkey,
    params: &UpdateMidpriceAndBaseSpreadParams,
    program_id: &Pubkey,
) -> Instruction {
    let sequence = params.sequence.unwrap_or(0);

    let mut data = Vec::with_capacity(25);
    data.push(Discriminator::UpdateMidpriceAndBaseSpread as u8);
    data.extend_from_slice(&sequence.to_le_bytes());
    data.extend_from_slice(&params.midprice_q32.to_le_bytes());
    data.extend_from_slice(&params.spread_factor_q32.to_le_bytes());

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

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