/**
 * This code was AUTOGENERATED using the codama library.
 * Please DO NOT EDIT THIS FILE, instead use visitors
 * to add features, then rerun codama to update it.
 *
 * @see https://github.com/codama-idl/codama
 */

import {
  Context,
  Pda,
  PublicKey,
  Signer,
  TransactionBuilder,
  publicKey,
  transactionBuilder,
} from '@metaplex-foundation/umi';
import {
  Serializer,
  mapSerializer,
  struct,
  u32,
  u64,
} from '@metaplex-foundation/umi/serializers';
import {
  ResolvedAccount,
  ResolvedAccountsWithIndices,
  getAccountMetasAndSigners,
} from '../shared';

// Accounts.
export type WithdrawNonceAccountInstructionAccounts = {
  nonceAccount: PublicKey | Pda;
  recipientAccount: PublicKey | Pda;
  recentBlockhashesSysvar?: PublicKey | Pda;
  rentSysvar?: PublicKey | Pda;
  nonceAuthority: Signer;
};

// Data.
export type WithdrawNonceAccountInstructionData = {
  discriminator: number;
  withdrawAmount: bigint;
};

export type WithdrawNonceAccountInstructionDataArgs = {
  withdrawAmount: number | bigint;
};

export function getWithdrawNonceAccountInstructionDataSerializer(): Serializer<
  WithdrawNonceAccountInstructionDataArgs,
  WithdrawNonceAccountInstructionData
> {
  return mapSerializer<
    WithdrawNonceAccountInstructionDataArgs,
    any,
    WithdrawNonceAccountInstructionData
  >(
    struct<WithdrawNonceAccountInstructionData>(
      [
        ['discriminator', u32()],
        ['withdrawAmount', u64()],
      ],
      { description: 'WithdrawNonceAccountInstructionData' }
    ),
    (value) => ({ ...value, discriminator: 5 })
  ) as Serializer<
    WithdrawNonceAccountInstructionDataArgs,
    WithdrawNonceAccountInstructionData
  >;
}

// Args.
export type WithdrawNonceAccountInstructionArgs =
  WithdrawNonceAccountInstructionDataArgs;

// Instruction.
export function withdrawNonceAccount(
  context: Pick<Context, 'programs'>,
  input: WithdrawNonceAccountInstructionAccounts &
    WithdrawNonceAccountInstructionArgs
): TransactionBuilder {
  // Program ID.
  const programId = context.programs.getPublicKey(
    'system',
    '11111111111111111111111111111111'
  );

  // Accounts.
  const resolvedAccounts = {
    nonceAccount: {
      index: 0,
      isWritable: true as boolean,
      value: input.nonceAccount ?? null,
    },
    recipientAccount: {
      index: 1,
      isWritable: true as boolean,
      value: input.recipientAccount ?? null,
    },
    recentBlockhashesSysvar: {
      index: 2,
      isWritable: false as boolean,
      value: input.recentBlockhashesSysvar ?? null,
    },
    rentSysvar: {
      index: 3,
      isWritable: false as boolean,
      value: input.rentSysvar ?? null,
    },
    nonceAuthority: {
      index: 4,
      isWritable: false as boolean,
      value: input.nonceAuthority ?? null,
    },
  } satisfies ResolvedAccountsWithIndices;

  // Arguments.
  const resolvedArgs: WithdrawNonceAccountInstructionArgs = { ...input };

  // Default values.
  if (!resolvedAccounts.recentBlockhashesSysvar.value) {
    resolvedAccounts.recentBlockhashesSysvar.value = publicKey(
      'SysvarRecentB1ockHashes11111111111111111111'
    );
  }
  if (!resolvedAccounts.rentSysvar.value) {
    resolvedAccounts.rentSysvar.value = publicKey(
      'SysvarRent111111111111111111111111111111111'
    );
  }

  // Accounts in order.
  const orderedAccounts: ResolvedAccount[] = Object.values(
    resolvedAccounts
  ).sort((a, b) => a.index - b.index);

  // Keys and Signers.
  const [keys, signers] = getAccountMetasAndSigners(
    orderedAccounts,
    'programId',
    programId
  );

  // Data.
  const data = getWithdrawNonceAccountInstructionDataSerializer().serialize(
    resolvedArgs as WithdrawNonceAccountInstructionDataArgs
  );

  // Bytes Created On Chain.
  const bytesCreatedOnChain = 0;

  return transactionBuilder([
    { instruction: { keys, programId, data }, signers, bytesCreatedOnChain },
  ]);
}
