// Core dependencies
import { BN, Program } from "@coral-xyz/anchor";
import { PublicKey, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY, TransactionInstruction } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

// Local imports
import { BasketsProgram } from "../../idl/types";
import { getAta, getBasketPda, getRebalanceStateAccount } from "../../utils/programAccounts";
import { WithdrawState } from "../../state/withdrawState";

export async function sellWithdrawBeforeRebalanceIx(params: {
    program: Program<BasketsProgram>,
    withdrawStateData: WithdrawState,
    payer: PublicKey,
    fromTokenMint: PublicKey,
}): Promise<TransactionInstruction> {
    // Destructure params
    const { program, withdrawStateData, payer, fromTokenMint } = params;

    const fromTokenIndex = withdrawStateData.compositionMints.findIndex(mint => mint.toBase58() === fromTokenMint.toBase58());
    const amountToWithdraw = parseInt(withdrawStateData.compositionAmounts[fromTokenIndex].toString());

    const toTokenMint = withdrawStateData.destinationMint;

    // Get withdraw state data and seeds
    const withdrawStateSeed = withdrawStateData.withdrawStateSeed;
    const basket = withdrawStateData.basket;

    // Get basket pda
    const basketPda = getBasketPda(basket);

    // Get token accounts
    const basketFromTokenAccount = getAta(basketPda, fromTokenMint);
    const workerFromTokenAccount = getAta(payer, fromTokenMint);
    const basketToTokenAccount = getAta(basketPda, toTokenMint);
    const workerToTokenAccount = getAta(payer, toTokenMint);

    // Get rebalance state
    const rebalanceState = getRebalanceStateAccount();

    // Build and return instruction
    return await program.methods
        .sellWithdrawBeforeRebalance(
            withdrawStateSeed,
            new BN(amountToWithdraw)
        )
        .accountsStrict({
            worker: payer,
            basket,
            basketPda,
            withdrawState: withdrawStateData.ownAddress,
            fromTokenMint,
            basketFromTokenAccount,
            workerFromTokenAccount,
            toTokenMint,
            basketToTokenAccount, 
            workerToTokenAccount,
            rebalanceState,
            instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
            systemProgram: SystemProgram.programId,
            tokenProgram: TOKEN_PROGRAM_ID,
        })
        .instruction();
}
