'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var mplCandyMachine = require('@metaplex-solarti/mpl-candy-machine');
var web3_js = require('@solarti/web3.js');
var helpers = require('../helpers.cjs');
var pdas = require('../pdas.cjs');
var program = require('../program.cjs');
var CandyMachineV2 = require('../models/CandyMachineV2.cjs');
var Amount = require('../../../types/Amount.cjs');
var Operation = require('../../../types/Operation.cjs');
var BigNumber = require('../../../types/BigNumber.cjs');
var PublicKey = require('../../../types/PublicKey.cjs');
var TransactionBuilder = require('../../../utils/TransactionBuilder.cjs');
var Signer = require('../../../types/Signer.cjs');
var SdkError = require('../../../errors/SdkError.cjs');

// -----------------
// Operation
// -----------------

const Key = 'CreateCandyMachineV2Operation';

/**
 * Creates a brand new Candy Machine.
 *
 * ```ts
 * const { candyMachine } = await metaplex
 *   .candyMachinesV2()
 *   .create({
 *     sellerFeeBasisPoints: 500, // 5% royalties
 *     price: sol(1.3), // 1.3 SOL
 *     itemsAvailable: toBigNumber(1000), // 1000 items available
 *   };
 * ```
 *
 * @group Operations
 * @category Constructors
 */
const createCandyMachineV2Operation = Operation.useOperation(Key);

/**
 * @group Operations
 * @category Types
 */

/**
 * @group Operations
 * @category Handlers
 */
const createCandyMachineV2OperationHandler = {
  async handle(operation, metaplex, scope) {
    const builder = await createCandyMachineV2Builder(metaplex, operation.input, scope);
    scope.throwIfCanceled();
    const confirmOptions = Operation.makeConfirmOptionsFinalizedOnMainnet(metaplex, scope.confirmOptions);
    const output = await builder.sendAndConfirm(metaplex, confirmOptions);
    scope.throwIfCanceled();
    const candyMachine = await metaplex.candyMachinesV2().findByAddress({
      address: output.candyMachineSigner.publicKey
    }, scope);
    return {
      ...output,
      candyMachine
    };
  }
};

// -----------------
// Builder
// -----------------

/**
 * @group Transaction Builders
 * @category Inputs
 */

/**
 * Creates a brand new Candy Machine.
 *
 * ```ts
 * const transactionBuilder = await metaplex
 *   .candyMachinesV2()
 *   .builders()
 *   .create({
 *     sellerFeeBasisPoints: 500, // 5% royalties
 *     price: sol(1.3), // 1.3 SOL
 *     itemsAvailable: toBigNumber(1000), // 1000 items available
 *   });
 * ```
 *
 * @group Transaction Builders
 * @category Constructors
 */
const createCandyMachineV2Builder = async (metaplex, params, options = {}) => {
  const {
    programs,
    payer = metaplex.rpc().getDefaultFeePayer()
  } = options;
  const candyMachine = params.candyMachine ?? web3_js.Keypair.generate();
  const authority = params.authority ?? metaplex.identity();
  const collection = params.collection ?? null;
  const {
    data,
    wallet,
    tokenMint
  } = CandyMachineV2.toCandyMachineV2InstructionData(candyMachine.publicKey, {
    ...params,
    wallet: params.wallet ?? metaplex.identity().publicKey,
    tokenMint: params.tokenMint ?? null,
    symbol: params.symbol ?? '',
    maxEditionSupply: params.maxEditionSupply ?? BigNumber.toBigNumber(0),
    isMutable: params.isMutable ?? true,
    retainAuthority: params.retainAuthority ?? true,
    goLiveDate: params.goLiveDate ?? null,
    endSettings: params.endSettings ?? null,
    creators: params.creators ?? [{
      address: metaplex.identity().publicKey,
      share: 100,
      verified: false
    }],
    hiddenSettings: params.hiddenSettings ?? null,
    whitelistMintSettings: params.whitelistMintSettings ?? null,
    gatekeeper: params.gatekeeper ?? null
  });
  const initializeInstruction = mplCandyMachine.createInitializeCandyMachineInstruction({
    candyMachine: candyMachine.publicKey,
    wallet,
    authority: PublicKey.toPublicKey(authority),
    payer: payer.publicKey
  }, {
    data
  });
  if (tokenMint) {
    initializeInstruction.keys.push({
      pubkey: tokenMint,
      isWritable: false,
      isSigner: false
    });
  } else {
    Amount.assertSameCurrencies(params.price, Amount.SOL);
  }
  return TransactionBuilder.TransactionBuilder.make().setFeePayer(payer).setContext({
    candyMachineSigner: candyMachine,
    wallet,
    authority: PublicKey.toPublicKey(authority),
    creators: data.creators
  })

  // Create an empty account for the candy machine.
  .add(await metaplex.system().builders().createAccount({
    newAccount: candyMachine,
    space: helpers.getCandyMachineV2AccountSizeFromData(data),
    program: program.CandyMachineV2Program.publicKey,
    instructionKey: params.createAccountInstructionKey ?? 'createAccount'
  }, {
    payer,
    programs
  }))

  // Initialize the candy machine account.
  .add({
    instruction: initializeInstruction,
    signers: [candyMachine, payer],
    key: params.initializeCandyMachineInstructionKey ?? 'initializeCandyMachine'
  })

  // Set the collection.
  .when(!!collection, builder => {
    if (!Signer.isSigner(authority)) {
      throw new SdkError.ExpectedSignerError('authority', 'PublicKey', {
        problemSuffix: 'You are trying to create a Candy Machine with a Collection NFT. ' + 'In order for the Collection NFT to be set successfully, you must provide the authority as a Signer.',
        solution: 'Please provide the "authority" parameter as a Signer if you want to set the Collection NFT upon creation. ' + 'Alternatively, you may remove the "collection" parameter to create a Candy Machine without an associated Collection NFT.'
      });
    }
    const collectionMint = collection;
    const metadata = metaplex.nfts().pdas().metadata({
      mint: collectionMint,
      programs
    });
    const edition = metaplex.nfts().pdas().masterEdition({
      mint: collectionMint,
      programs
    });
    const collectionPda = pdas.findCandyMachineV2CollectionPda(candyMachine.publicKey);
    const collectionAuthorityRecord = metaplex.nfts().pdas().collectionAuthorityRecord({
      mint: collectionMint,
      collectionAuthority: collectionPda,
      programs
    });
    return builder.add({
      instruction: mplCandyMachine.createSetCollectionInstruction({
        candyMachine: candyMachine.publicKey,
        authority: PublicKey.toPublicKey(authority),
        collectionPda,
        payer: payer.publicKey,
        metadata,
        mint: collectionMint,
        edition,
        collectionAuthorityRecord,
        tokenMetadataProgram: metaplex.programs().getTokenMetadata().address
      }),
      signers: [authority],
      key: params.setCollectionInstructionKey ?? 'setCollection'
    });
  });
};

exports.createCandyMachineV2Builder = createCandyMachineV2Builder;
exports.createCandyMachineV2Operation = createCandyMachineV2Operation;
exports.createCandyMachineV2OperationHandler = createCandyMachineV2OperationHandler;
//# sourceMappingURL=createCandyMachineV2.cjs.map
