import { Buffer } from 'buffer';
import { CandyMachine as MplCandyMachine, candyMachineBeet, } from '@metaplex-foundation/mpl-candy-machine-core';
import { CANDY_MACHINE_HIDDEN_SECTION } from '../constants';
import { deserializeCandyMachineHiddenSection } from './CandyMachineHiddenSection';
import { assertModel, createSerializerFromSolitaType, deserializeAccount, deserializeFeatureFlags, isModel, toAccountInfo, toBigNumber, } from '../../../types';
import { assert, removeEmptyChars } from '../../../utils';
/** @group Model Helpers */
export const isCandyMachine = (value) => isModel('candyMachine', value);
/** @group Model Helpers */
export function assertCandyMachine(value) {
    assertModel(isCandyMachine(value), `Expected CandyMachine model`);
}
/** @group Model Helpers */
export const toCandyMachine = (account, candyGuard = null) => {
    const serializer = createSerializerFromSolitaType(MplCandyMachine, candyMachineBeet.description);
    const parsedAccount = deserializeAccount(account, serializer);
    const itemsAvailable = toBigNumber(parsedAccount.data.data.itemsAvailable);
    const itemsMinted = toBigNumber(parsedAccount.data.itemsRedeemed);
    const itemsRemaining = toBigNumber(itemsAvailable.sub(itemsMinted));
    let items = [];
    let itemsLoaded = 0;
    let isFullyLoaded = true;
    const { hiddenSettings } = parsedAccount.data.data;
    const { configLineSettings } = parsedAccount.data.data;
    let itemSettings;
    if (hiddenSettings) {
        itemSettings = Object.assign(Object.assign({}, hiddenSettings), { type: 'hidden' });
    }
    else {
        assert(!!configLineSettings, 'Expected either hidden or config line settings');
        itemSettings = Object.assign(Object.assign({}, configLineSettings), { type: 'configLines' });
        const hiddenSection = deserializeCandyMachineHiddenSection(account.data, itemsAvailable.toNumber(), itemsRemaining.toNumber(), itemSettings, CANDY_MACHINE_HIDDEN_SECTION);
        items = hiddenSection.items;
        itemsLoaded = hiddenSection.itemsLoaded;
        isFullyLoaded = hiddenSection.itemsLoaded >= itemsAvailable.toNumber();
    }
    return {
        model: 'candyMachine',
        address: account.publicKey,
        accountInfo: toAccountInfo(account),
        authorityAddress: parsedAccount.data.authority,
        mintAuthorityAddress: parsedAccount.data.mintAuthority,
        collectionMintAddress: parsedAccount.data.collectionMint,
        symbol: removeEmptyChars(parsedAccount.data.data.symbol),
        sellerFeeBasisPoints: parsedAccount.data.data.sellerFeeBasisPoints,
        isMutable: parsedAccount.data.data.isMutable,
        maxEditionSupply: toBigNumber(parsedAccount.data.data.maxSupply),
        creators: parsedAccount.data.data.creators.map((creator) => (Object.assign(Object.assign({}, creator), { share: creator.percentageShare }))),
        items,
        itemsAvailable,
        itemsMinted,
        itemsRemaining,
        itemsLoaded,
        isFullyLoaded,
        itemSettings,
        featureFlags: deserializeFeatureFlags(toBigNumber(parsedAccount.data.features).toArrayLike(Buffer, 'le', 8), 64)[0],
        candyGuard,
    };
};
export const toCandyMachineData = (candyMachine) => {
    return {
        itemsAvailable: candyMachine.itemsAvailable,
        symbol: candyMachine.symbol,
        sellerFeeBasisPoints: candyMachine.sellerFeeBasisPoints,
        maxSupply: candyMachine.maxEditionSupply,
        isMutable: candyMachine.isMutable,
        creators: candyMachine.creators.map((creator) => (Object.assign(Object.assign({}, creator), { verified: false, percentageShare: creator.share }))),
        configLineSettings: candyMachine.itemSettings.type === 'configLines'
            ? candyMachine.itemSettings
            : null,
        hiddenSettings: candyMachine.itemSettings.type === 'hidden'
            ? candyMachine.itemSettings
            : null,
    };
};
export const getCandyMachineSize = (data) => {
    if (data.hiddenSettings) {
        return CANDY_MACHINE_HIDDEN_SECTION;
    }
    // This should not happen as the candy machine input type
    // ensures exactly on of them is provided.
    assert(!!data.configLineSettings, 'No config line settings nor hidden settings were provided. ' +
        'Please provide one of them.');
    const itemsAvailable = toBigNumber(data.itemsAvailable).toNumber();
    const configLineSize = data.configLineSettings.nameLength + data.configLineSettings.uriLength;
    return Math.ceil(CANDY_MACHINE_HIDDEN_SECTION +
        // Number of currently items inserted.
        4 +
        // Config line data.
        itemsAvailable * configLineSize +
        // Bit mask to keep track of which ConfigLines have been added.
        (4 + Math.floor(itemsAvailable / 8) + 1) +
        // Mint indices.
        (4 + itemsAvailable * 4));
};
//# sourceMappingURL=CandyMachine.js.map