import { PublicKey } from '@solarti/web3.js';
import { parseCandyMachineV2Account, parseCandyMachineV2CollectionAccount } from '../accounts.mjs';
import { findCandyMachineV2CollectionPda } from '../pdas.mjs';
import { CandyMachineV2Program } from '../program.mjs';
import { zipMap } from '../../../utils/common.mjs';
import { useOperation } from '../../../types/Operation.mjs';
import { UnreachableCaseError } from '../../../errors/SdkError.mjs';
import { toMint } from '../../tokenModule/models/Mint.mjs';
import { toMintAccount } from '../../tokenModule/accounts.mjs';
import { toCandyMachineV2 } from '../models/CandyMachineV2.mjs';

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

const Key = 'FindCandyMachinesV2ByPublicKeyOperation';

/**
 * Find all Candy Machines matching by a given `publicKey` or a given `type`.
 *
 * The following two types are supported.
 *
 * `authority`: Find Candy Machines whose authority is the given `publicKey`.
 * ```ts
 * const someAuthority = new PublicKey('...');
 * const candyMachines = await metaplex
 *   .candyMachinesV2()
 *   .findAllBy({ type: 'authority', someAuthority });
 * ```
 *
 * `wallet`: Find Candy Machines whose wallet address is the given `publicKey`.
 * ```ts
 * const someWallet = new PublicKey('...');
 * const candyMachines = await metaplex
 *   .candyMachinesV2()
 *   .findAllBy({ type: 'wallet', someWallet });
 * ```
 *
 * @group Operations
 * @category Constructors
 */
const findCandyMachinesV2ByPublicKeyFieldOperation = useOperation(Key);

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

/**
 * @group Operations
 * @category Handlers
 */
const findCandyMachinesV2ByPublicKeyFieldOperationHandler = {
  handle: async (operation, metaplex, scope) => {
    const {
      commitment
    } = scope;
    const {
      type,
      publicKey
    } = operation.input;
    const accounts = CandyMachineV2Program.accounts(metaplex).mergeConfig({
      commitment
    });
    let candyMachineQuery;
    switch (type) {
      case 'authority':
        candyMachineQuery = accounts.candyMachineAccountsForAuthority(publicKey);
        break;
      case 'wallet':
        candyMachineQuery = accounts.candyMachineAccountsForWallet(publicKey);
        break;
      default:
        throw new UnreachableCaseError(type);
    }
    const unparsedAccounts = await candyMachineQuery.get();
    scope.throwIfCanceled();
    const collectionPdas = unparsedAccounts.map(unparsedAccount => findCandyMachineV2CollectionPda(unparsedAccount.publicKey));

    // Find mint details for all unique SPL tokens used
    // in candy machines that have non-null `tokenMint`

    const parsedAccounts = Object.fromEntries(unparsedAccounts.map(unparsedAccount => [unparsedAccount.publicKey.toString(), parseCandyMachineV2Account(unparsedAccount)]));
    const tokenMints = [...new Set(Object.values(parsedAccounts).map(account => account.data.tokenMint?.toString()).filter(tokenMint => tokenMint !== undefined))].map(address => new PublicKey(address));
    const result = await metaplex.rpc().getMultipleAccounts(tokenMints.concat(collectionPdas), commitment);
    scope.throwIfCanceled();
    const unparsedMintAccounts = result.slice(0, tokenMints.length);
    const unparsedCollectionAccounts = result.slice(-collectionPdas.length);
    const mints = Object.fromEntries(unparsedMintAccounts.map(account => [account.publicKey.toString(), toMint(toMintAccount(account))]));
    return zipMap(unparsedAccounts, unparsedCollectionAccounts, (unparsedAccount, unparsedCollectionAccount) => {
      const parsedAccount = parsedAccounts[unparsedAccount.publicKey.toString()];
      const collectionAccount = unparsedCollectionAccount ? parseCandyMachineV2CollectionAccount(unparsedCollectionAccount) : null;
      const tokenMintAddress = parsedAccount.data.tokenMint?.toString();
      return toCandyMachineV2(parsedAccount, unparsedAccount, collectionAccount, tokenMintAddress ? mints[tokenMintAddress] : null);
    });
  }
};

export { findCandyMachinesV2ByPublicKeyFieldOperation, findCandyMachinesV2ByPublicKeyFieldOperationHandler };
//# sourceMappingURL=findCandyMachinesV2ByPublicKeyField.mjs.map
