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

// Local imports
import { PYTHNET_CUSTODY_PRICE_SOL_ACCOUNT, PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT } from "../../utils/constants";
import { BasketsProgram } from "../../idl/types";
import { getAta, getDepositFeesWallet} from "../../utils/programAccounts";
import { fetchBasketState } from "../../state/basket";


export async function depositIx(params: {
    program: Program<BasketsProgram>,
    buyer: PublicKey,
    basket: PublicKey,
    depositAmount: number,
    depositMint: PublicKey,
}): Promise<TransactionInstruction> {
    // Destructure program from params
    const { program } = params;

    // Get basket state and find token index
    const basketState = await fetchBasketState(program, params.basket);
    const tokenIndex = basketState.compositionMints.findIndex(
        mint => mint.equals(params.depositMint)
    );

    // Get basket PDA
    const basketPda = basketState.basketPda;

    // Derive all required token accounts
    const buyerBasketTokenAccount = getAta(params.buyer, basketState.mint);
    const buyerDepositTokenAccount = getAta(params.buyer, params.depositMint);
    const basketDepositTokenAccount = getAta(basketPda, params.depositMint);
    const basketDepositFeesWallet = getDepositFeesWallet(params.basket);
    const basketDepositFeesTokenAccount = getAta(basketDepositFeesWallet, basketState.mint);

    // Build and return instruction
    return await program.methods
        .basketBuy(
            new BN(params.depositAmount),
        )
        .accountsStrict({
            buyer: params.buyer,
            basket: params.basket,
            basketPda,
            basketTokenMint: basketState.mint,
            buyerBasketTokenAccount,
            depositTokenMint: params.depositMint,
            buyerDepositTokenAccount,
            basketDepositTokenAccount,
            usdcPriceOracle: PYTHNET_CUSTODY_PRICE_USDC_ACCOUNT,
            solPriceOracle: PYTHNET_CUSTODY_PRICE_SOL_ACCOUNT,
            oracleAccount1: basketState.compositionOracle1[tokenIndex],
            oracleAccount2: basketState.compositionOracle2[tokenIndex],
            basketDepositFeesWallet,
            basketDepositFeesTokenAccount,
            associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
            systemProgram: SystemProgram.programId,
            tokenProgram: TOKEN_PROGRAM_ID,
        })
        .instruction();
}
