var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import { createRemoveCollectionInstruction, createSetCollectionInstruction, createUpdateAuthorityInstruction, createUpdateCandyMachineInstruction, } from '@metaplex-solarti/mpl-candy-machine';
import isEqual from 'lodash.isequal';
import { toCandyMachineV2Configs, toCandyMachineV2InstructionData, } from '../models';
import { findCandyMachineV2CollectionPda } from '../pdas';
import { TransactionBuilder } from '../../../utils';
import { useOperation, } from '../../../types';
import { NoInstructionsToSendError } from '../../../errors';
// -----------------
// Operation
// -----------------
const Key = 'UpdateCandyMachineV2Operation';
/**
 * Updates an existing Candy Machine.
 *
 * ```ts
 * await metaplex
 *   .candyMachinesV2()
 *   .update({
 *     candyMachine,
 *     price: sol(2), // Updates the price only.
 *   };
 * ```
 *
 * @group Operations
 * @category Constructors
 */
export const updateCandyMachineV2Operation = useOperation(Key);
/**
 * @group Operations
 * @category Handlers
 */
export const updateCandyMachineV2OperationHandler = {
    handle(operation, metaplex, scope) {
        return __awaiter(this, void 0, void 0, function* () {
            const _a = operation.input, { candyMachine, authority = metaplex.identity(), newAuthority, newCollection } = _a, updatableFields = __rest(_a, ["candyMachine", "authority", "newAuthority", "newCollection"]);
            const currentConfigs = toCandyMachineV2Configs(candyMachine);
            const instructionDataWithoutChanges = toCandyMachineV2InstructionData(candyMachine.address, currentConfigs);
            const instructionData = toCandyMachineV2InstructionData(candyMachine.address, Object.assign(Object.assign({}, currentConfigs), updatableFields));
            const { data, wallet, tokenMint } = instructionData;
            const shouldUpdateData = !isEqual(instructionData, instructionDataWithoutChanges);
            const builder = updateCandyMachineV2Builder(metaplex, {
                candyMachine,
                authority,
                newData: shouldUpdateData
                    ? Object.assign(Object.assign({}, data), { wallet, tokenMint }) : undefined,
                newCollection,
                newAuthority,
            }, scope);
            if (builder.isEmpty()) {
                throw new NoInstructionsToSendError(Key);
            }
            return builder.sendAndConfirm(metaplex, scope.confirmOptions);
        });
    },
};
/**
 * Updates an existing Candy Machine.
 *
 * ```ts
 * const transactionBuilder = metaplex
 *   .candyMachinesV2()
 *   .builders()
 *   .update({
 *     candyMachine: { address, walletAddress, collectionMintAddress },
 *     newData: {...}, // Updates the provided data.
 *   });
 * ```
 *
 * @group Transaction Builders
 * @category Constructors
 */
export const updateCandyMachineV2Builder = (metaplex, params, options = {}) => {
    const { programs, payer = metaplex.rpc().getDefaultFeePayer() } = options;
    const { candyMachine, authority = metaplex.identity(), newData, newAuthority, newCollection, } = params;
    const tokenMetadataProgram = metaplex
        .programs()
        .getTokenMetadata(programs).address;
    const shouldUpdateAuthority = !!newAuthority && !newAuthority.equals(authority.publicKey);
    const sameCollection = newCollection &&
        candyMachine.collectionMintAddress &&
        candyMachine.collectionMintAddress.equals(newCollection);
    const shouldUpdateCollection = !!newCollection && !sameCollection;
    const shouldRemoveCollection = !shouldUpdateCollection &&
        newCollection === null &&
        candyMachine.collectionMintAddress !== null;
    return (TransactionBuilder.make()
        .setFeePayer(payer)
        // Update data.
        .when(!!newData, (builder) => {
        var _a;
        const data = newData;
        const wallet = newData === null || newData === void 0 ? void 0 : newData.wallet;
        const tokenMint = newData === null || newData === void 0 ? void 0 : newData.tokenMint;
        const updateInstruction = createUpdateCandyMachineInstruction({
            candyMachine: candyMachine.address,
            authority: authority.publicKey,
            wallet,
        }, { data });
        if (tokenMint) {
            updateInstruction.keys.push({
                pubkey: tokenMint,
                isWritable: false,
                isSigner: false,
            });
        }
        return builder.add({
            instruction: updateInstruction,
            signers: [authority],
            key: (_a = params.updateInstructionKey) !== null && _a !== void 0 ? _a : 'update',
        });
    })
        // Set or update collection.
        .when(shouldUpdateCollection, (builder) => {
        var _a;
        const collectionMint = newCollection;
        const metadata = metaplex.nfts().pdas().metadata({
            mint: collectionMint,
            programs,
        });
        const edition = metaplex.nfts().pdas().masterEdition({
            mint: collectionMint,
            programs,
        });
        const collectionPda = findCandyMachineV2CollectionPda(candyMachine.address);
        const collectionAuthorityRecord = metaplex
            .nfts()
            .pdas()
            .collectionAuthorityRecord({
            mint: collectionMint,
            collectionAuthority: collectionPda,
            programs,
        });
        return builder.add({
            instruction: createSetCollectionInstruction({
                candyMachine: candyMachine.address,
                authority: authority.publicKey,
                collectionPda,
                payer: payer.publicKey,
                metadata,
                mint: collectionMint,
                edition,
                collectionAuthorityRecord,
                tokenMetadataProgram,
            }),
            signers: [payer, authority],
            key: (_a = params.setCollectionInstructionKey) !== null && _a !== void 0 ? _a : 'setCollection',
        });
    })
        // Remove collection.
        .when(shouldRemoveCollection, (builder) => {
        var _a;
        const collectionMint = candyMachine.collectionMintAddress;
        const metadata = metaplex.nfts().pdas().metadata({
            mint: collectionMint,
            programs,
        });
        const collectionPda = findCandyMachineV2CollectionPda(candyMachine.address);
        const collectionAuthorityRecord = metaplex
            .nfts()
            .pdas()
            .collectionAuthorityRecord({
            mint: collectionMint,
            collectionAuthority: collectionPda,
            programs,
        });
        return builder.add({
            instruction: createRemoveCollectionInstruction({
                candyMachine: candyMachine.address,
                authority: authority.publicKey,
                collectionPda,
                metadata,
                mint: collectionMint,
                collectionAuthorityRecord,
                tokenMetadataProgram,
            }),
            signers: [authority],
            key: (_a = params.removeCollectionInstructionKey) !== null && _a !== void 0 ? _a : 'removeCollection',
        });
    })
        // Update authority.
        .when(shouldUpdateAuthority, (builder) => {
        var _a, _b;
        return builder.add({
            instruction: createUpdateAuthorityInstruction({
                candyMachine: candyMachine.address,
                authority: authority.publicKey,
                wallet: (_a = newData === null || newData === void 0 ? void 0 : newData.wallet) !== null && _a !== void 0 ? _a : candyMachine.walletAddress,
            }, { newAuthority: newAuthority }),
            signers: [authority],
            key: (_b = params.updateAuthorityInstructionKey) !== null && _b !== void 0 ? _b : 'updateAuthority',
        });
    }));
};
//# sourceMappingURL=updateCandyMachineV2.js.map