use crate::{
    config::Config,
    log_context,
    transaction::{
        build_transaction_sync, get_compute_budget_price, get_lock_writable_accounts,
        process_transaction,
    },
};
use anyhow::{anyhow, Result};
use borsh::BorshSerialize;
use riptide_amm::{fetch_market, to_q64_64, OracleData, OracleUpdate, OracleUpdateInstructionArgs};
use solana_pubkey::Pubkey;
use solana_signer::Signer;

pub fn handle(config: &Config, market: &Pubkey, price: &f64) -> Result<()> {
    let rpc = config.rpc_client();

    let market = fetch_market(&rpc, market)?;
    let next_sequence = market.data.sequence + 1;

    let signer = config
        .authority(&market.data.updater)
        .ok_or(anyhow!("Signer not found"))?;

    let valid_until = rpc.get_slot()? + 5;

    let price = to_q64_64(*price, 6, 6);

    let mut data = [0u8; 512];
    OracleData::FlatPrice {
        price_q64_64: price,
    }
    .serialize(&mut data.as_mut_slice())?;

    log_context!(
      market => market.address,
      sequence => next_sequence,
      price => price,
      mint_a => market.data.mint_a,
      mint_b => market.data.mint_b,
    );

    let ix = OracleUpdate {
        updater: signer.pubkey(),
        market: market.address,
    }
    .instruction(OracleUpdateInstructionArgs {
        sequence: next_sequence,
        valid_until,
        data,
    });

    let compute_budget_limit = 500;
    let lock_writable_accounts = get_lock_writable_accounts(std::slice::from_ref(&ix));
    let loaded_accounts_data_size = 1024;
    let compute_unit_price = get_compute_budget_price(&rpc, &lock_writable_accounts);
    let blockhash = rpc.get_latest_blockhash()?;

    let tx = build_transaction_sync(
        &blockhash,
        &signer.pubkey(),
        Some(compute_budget_limit),
        Some(compute_unit_price),
        Some(loaded_accounts_data_size),
        &[ix],
    )?;

    process_transaction(&rpc, &[signer], tx)
}
