use anyhow::{anyhow, Result};
use riptide_amm::{
    get_market_address, MarketInitialize, MarketInitializeInstructionArgs, MarketUpdate,
    MarketUpdateInstructionArgs, MarketUpdateType,
};
use std::fs::write;

use solana_keypair::Keypair;
use solana_pubkey::Pubkey;

use solana_signer::Signer;
use spl_associated_token_account_interface::address::get_associated_token_address_with_program_id;

use crate::{config::Config, log_context, transaction::process_instructions, INIT_AUTHORITY};

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

    let market_id = rand::random::<u32>();
    let market_address = get_market_address(market_id).unwrap().0;

    let mint_a_account = rpc.get_account(mint_a)?;
    let mint_b_account = rpc.get_account(mint_b)?;

    let updater = Keypair::new();
    let path = format!("{}.json", updater.pubkey());
    let bytes = serde_json::to_string(&updater.to_bytes().to_vec())?;
    write(&path, bytes)?;

    log_context!(
        market => market_address.to_string(),
        mint_a => mint_a.to_string(),
        mint_b => mint_b.to_string(),
    );

    let authority = config
        .authority(&INIT_AUTHORITY)
        .ok_or(anyhow!("Update authority not found"))?;

    let market_a = get_associated_token_address_with_program_id(
        &market_address,
        mint_a,
        &mint_a_account.owner,
    );

    let market_b = get_associated_token_address_with_program_id(
        &market_address,
        mint_b,
        &mint_b_account.owner,
    );

    let ixs = [
        MarketInitialize {
            authority: INIT_AUTHORITY,
            market: market_address,
            mint_a: *mint_a,
            mint_b: *mint_b,
            market_a,
            market_b,
            system_program: solana_system_interface::program::ID,
            ata_program: spl_associated_token_account_interface::program::ID,
            token_program_a: mint_a_account.owner,
            token_program_b: mint_b_account.owner,
        }
        .instruction(MarketInitializeInstructionArgs { market_id }),
        MarketUpdate {
            authority: INIT_AUTHORITY,
            market: market_address,
            system_program: solana_system_interface::program::ID,
        }
        .instruction(MarketUpdateInstructionArgs {
            update: MarketUpdateType::Updater(updater.pubkey()),
        }),
    ];

    process_instructions(&rpc, &[authority], &ixs)
}
