// 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, getRebalanceStateAccount } from "../../utils/programAccounts";
import { BasketState } from "../../state/basket";

export async function withdrawBeforeRebalanceIx(params: {
    program: Program<BasketsProgram>,
    basketState: BasketState,
    payer: PublicKey,
    fromTokenMint: PublicKey,
    toTokenMint: PublicKey,
    amountToWithdraw: number,
    checkWeights: boolean,
    fromTokenWeight: number,
    toTokenWeight: number,
}): Promise<TransactionInstruction> {
    const { program, basketState } = params;
    const basketPda = basketState.basketPda;
    const basketFromTokenAccount = getAta(basketPda, params.fromTokenMint);
    const workerFromTokenAccount = getAta(params.payer, params.fromTokenMint);
    const basketToTokenAccount = getAta(basketPda, params.toTokenMint);
    const workerToTokenAccount = getAta(params.payer, params.toTokenMint);
    const rebalanceState = getRebalanceStateAccount();
    const ix = await program.methods
        .basketWithdrawBeforeRebalance(
            params.checkWeights == true ? 1 : 0,
            new BN(params.amountToWithdraw),
            params.fromTokenWeight,
            params.toTokenWeight,
        ).accountsStrict({
            worker: params.payer,
            basket: basketState.ownAddress,
            basketPda,
            fromTokenMint: params.fromTokenMint,
            basketFromTokenAccount,
            workerFromTokenAccount,
            toTokenMint: params.toTokenMint,
            basketToTokenAccount,
            workerToTokenAccount,
            rebalanceState,
            instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
            systemProgram: SystemProgram.programId,
            tokenProgram: TOKEN_PROGRAM_ID,
        }).instruction();
    return ix;
}
