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

// Local imports
import { BasketsProgram } from "../../idl/types";
import { getBasketPda, getBasketTokenMintAccount, getMetadataAccount } from "../../utils/programAccounts";
import { METADATA_PROGRAM_ID } from "../../utils/metadataUtils";
import { MANAGERS_PER_BASKET } from "../../utils/constants";


export async function editBasketIx(params: {
    program: Program<BasketsProgram>,
    creator: PublicKey,
    basket: PublicKey,
    basketType: number,
    creatorDepositFeeBps: number,
    creatorManagementFeeBps: number,
    creatorPerformanceFeeBps: number,
    host: PublicKey,
    hostDepositFeeBps: number,
    hostManagementFeeBps: number,
    hostPerformanceFeeBps: number,
    managers: PublicKey[],
    managersWeightBps: number[],
    managersAuthority: number[],
    managersDepositFeeBps: number,
    managersManagementFeeBps: number,
    managersPerformanceFeeBps: number,
    basketDepositFeeBps: number,
    basketWithdrawFeeBps: number,
    rebalanceIntervalSeconds: number,
    rebalanceThresholdBps: number,
    rebalanceSlippageBps: number,
    lpThresholdBps: number,
    allowAutomation: boolean,
    allowLp: boolean,
    name: string,
    symbol: string,
    uri: string,
}): Promise<TransactionInstruction> {
    // Destructure required params
    const { program, creator, basket } = params;

    while (params.managers.length < MANAGERS_PER_BASKET) {
        params.managers.push(PublicKey.default);
    }
    while (params.managersWeightBps.length < MANAGERS_PER_BASKET) {
        params.managersWeightBps.push(0);
    }
    while (params.managersAuthority.length < MANAGERS_PER_BASKET) {
        params.managersAuthority.push(0);
    }

    // Get basket state and derive required accounts
    const basketPda = getBasketPda(basket);
    const tokenMint = getBasketTokenMintAccount(basket);
    const metadataAccount = getMetadataAccount(tokenMint);

    // Build and return instruction
    return await program.methods
        .editBasket(
            params.basketType,
            new BN(params.creatorDepositFeeBps),
            new BN(params.creatorManagementFeeBps),
            new BN(params.creatorPerformanceFeeBps),
            params.host,
            new BN(params.hostDepositFeeBps),
            new BN(params.hostManagementFeeBps),
            new BN(params.hostPerformanceFeeBps),
            params.managers,
            params.managersWeightBps,
            params.managersAuthority,
            params.managersDepositFeeBps,
            params.managersManagementFeeBps,
            params.managersPerformanceFeeBps,
            new BN(params.basketDepositFeeBps),
            new BN(params.basketWithdrawFeeBps),
            new BN(params.rebalanceIntervalSeconds),
            new BN(params.rebalanceThresholdBps),
            new BN(params.rebalanceSlippageBps),
            new BN(params.lpThresholdBps),
            params.allowAutomation ? 1 : 0,
            params.allowLp ? 1 : 0,
            {
                name: params.name,
                symbol: params.symbol,
                uri: params.uri,
            }
        )
        .accountsStrict({
            creator,
            basket,
            basketPda,
            metadataAccount,
            metadataProgram: METADATA_PROGRAM_ID,
        })
        .instruction();
}
