/**
 * 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 {
  assertIsInstructionWithAccounts,
  containsBytes,
  extendClient,
  getU8Encoder,
  SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_INSTRUCTION,
  SOLANA_ERROR__PROGRAM_CLIENTS__UNRECOGNIZED_INSTRUCTION_TYPE,
  SolanaError,
  type Address,
  type ClientWithRpc,
  type ClientWithTransactionPlanning,
  type ClientWithTransactionSending,
  type ExtendedClient,
  type GetAccountInfoApi,
  type GetMultipleAccountsApi,
  type Instruction,
  type InstructionWithData,
  type ReadonlyUint8Array,
} from "@solana/kit";
import {
  addSelfFetchFunctions,
  addSelfPlanAndSendFunctions,
  type SelfFetchFunctions,
  type SelfPlanAndSendFunctions,
} from "@solana/kit/program-client-core";
import {
  getAllowedMintCodec,
  getInstanceCodec,
  getOperatorCodec,
  type AllowedMint,
  type AllowedMintArgs,
  type Instance,
  type InstanceArgs,
  type Operator,
  type OperatorArgs,
} from "../accounts";
import {
  getAddOperatorInstructionAsync,
  getAllowMintInstructionAsync,
  getBlockMintInstructionAsync,
  getCreateInstanceInstructionAsync,
  getDepositInstructionAsync,
  getReleaseFundsInstructionAsync,
  getRemoveOperatorInstructionAsync,
  getResetSmtRootInstructionAsync,
  getSetNewAdminInstructionAsync,
  parseAddOperatorInstruction,
  parseAllowMintInstruction,
  parseBlockMintInstruction,
  parseCreateInstanceInstruction,
  parseDepositInstruction,
  parseReleaseFundsInstruction,
  parseRemoveOperatorInstruction,
  parseResetSmtRootInstruction,
  parseSetNewAdminInstruction,
  type AddOperatorAsyncInput,
  type AllowMintAsyncInput,
  type BlockMintAsyncInput,
  type CreateInstanceAsyncInput,
  type DepositAsyncInput,
  type ParsedAddOperatorInstruction,
  type ParsedAllowMintInstruction,
  type ParsedBlockMintInstruction,
  type ParsedCreateInstanceInstruction,
  type ParsedDepositInstruction,
  type ParsedReleaseFundsInstruction,
  type ParsedRemoveOperatorInstruction,
  type ParsedResetSmtRootInstruction,
  type ParsedSetNewAdminInstruction,
  type ReleaseFundsAsyncInput,
  type RemoveOperatorAsyncInput,
  type ResetSmtRootAsyncInput,
  type SetNewAdminAsyncInput,
} from "../instructions";
import {
  findAllowedMintPda,
  findEventAuthorityPda,
  findInstancePda,
  findOperatorPda,
} from "../pdas";

export const PRIVATE_CHANNEL_ESCROW_PROGRAM_PROGRAM_ADDRESS =
  "9tgHa1DcnaSSUtmMsst8ovKTe1Gfxzezn27KnH9xXYeU" as Address<"9tgHa1DcnaSSUtmMsst8ovKTe1Gfxzezn27KnH9xXYeU">;

export enum PrivateChannelEscrowProgramAccount {
  AllowedMint,
  Instance,
  Operator,
}

export enum PrivateChannelEscrowProgramInstruction {
  CreateInstance,
  AllowMint,
  BlockMint,
  AddOperator,
  RemoveOperator,
  SetNewAdmin,
  Deposit,
  ReleaseFunds,
  ResetSmtRoot,
}

export function identifyPrivateChannelEscrowProgramInstruction(
  instruction: { data: ReadonlyUint8Array } | ReadonlyUint8Array,
): PrivateChannelEscrowProgramInstruction {
  const data = "data" in instruction ? instruction.data : instruction;
  if (containsBytes(data, getU8Encoder().encode(0), 0)) {
    return PrivateChannelEscrowProgramInstruction.CreateInstance;
  }
  if (containsBytes(data, getU8Encoder().encode(1), 0)) {
    return PrivateChannelEscrowProgramInstruction.AllowMint;
  }
  if (containsBytes(data, getU8Encoder().encode(2), 0)) {
    return PrivateChannelEscrowProgramInstruction.BlockMint;
  }
  if (containsBytes(data, getU8Encoder().encode(3), 0)) {
    return PrivateChannelEscrowProgramInstruction.AddOperator;
  }
  if (containsBytes(data, getU8Encoder().encode(4), 0)) {
    return PrivateChannelEscrowProgramInstruction.RemoveOperator;
  }
  if (containsBytes(data, getU8Encoder().encode(5), 0)) {
    return PrivateChannelEscrowProgramInstruction.SetNewAdmin;
  }
  if (containsBytes(data, getU8Encoder().encode(6), 0)) {
    return PrivateChannelEscrowProgramInstruction.Deposit;
  }
  if (containsBytes(data, getU8Encoder().encode(7), 0)) {
    return PrivateChannelEscrowProgramInstruction.ReleaseFunds;
  }
  if (containsBytes(data, getU8Encoder().encode(8), 0)) {
    return PrivateChannelEscrowProgramInstruction.ResetSmtRoot;
  }
  throw new SolanaError(
    SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_INSTRUCTION,
    { instructionData: data, programName: "privateChannelEscrowProgram" },
  );
}

export type ParsedPrivateChannelEscrowProgramInstruction<
  TProgram extends string = "9tgHa1DcnaSSUtmMsst8ovKTe1Gfxzezn27KnH9xXYeU",
> =
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.CreateInstance;
    } & ParsedCreateInstanceInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.AllowMint;
    } & ParsedAllowMintInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.BlockMint;
    } & ParsedBlockMintInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.AddOperator;
    } & ParsedAddOperatorInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.RemoveOperator;
    } & ParsedRemoveOperatorInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.SetNewAdmin;
    } & ParsedSetNewAdminInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.Deposit;
    } & ParsedDepositInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.ReleaseFunds;
    } & ParsedReleaseFundsInstruction<TProgram>)
  | ({
      instructionType: PrivateChannelEscrowProgramInstruction.ResetSmtRoot;
    } & ParsedResetSmtRootInstruction<TProgram>);

export function parsePrivateChannelEscrowProgramInstruction<
  TProgram extends string,
>(
  instruction: Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array>,
): ParsedPrivateChannelEscrowProgramInstruction<TProgram> {
  const instructionType =
    identifyPrivateChannelEscrowProgramInstruction(instruction);
  switch (instructionType) {
    case PrivateChannelEscrowProgramInstruction.CreateInstance: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.CreateInstance,
        ...parseCreateInstanceInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.AllowMint: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.AllowMint,
        ...parseAllowMintInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.BlockMint: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.BlockMint,
        ...parseBlockMintInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.AddOperator: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.AddOperator,
        ...parseAddOperatorInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.RemoveOperator: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.RemoveOperator,
        ...parseRemoveOperatorInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.SetNewAdmin: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.SetNewAdmin,
        ...parseSetNewAdminInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.Deposit: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.Deposit,
        ...parseDepositInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.ReleaseFunds: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.ReleaseFunds,
        ...parseReleaseFundsInstruction(instruction),
      };
    }
    case PrivateChannelEscrowProgramInstruction.ResetSmtRoot: {
      assertIsInstructionWithAccounts(instruction);
      return {
        instructionType: PrivateChannelEscrowProgramInstruction.ResetSmtRoot,
        ...parseResetSmtRootInstruction(instruction),
      };
    }
    default:
      throw new SolanaError(
        SOLANA_ERROR__PROGRAM_CLIENTS__UNRECOGNIZED_INSTRUCTION_TYPE,
        {
          instructionType: instructionType as string,
          programName: "privateChannelEscrowProgram",
        },
      );
  }
}

export type PrivateChannelEscrowProgramPlugin = {
  accounts: PrivateChannelEscrowProgramPluginAccounts;
  instructions: PrivateChannelEscrowProgramPluginInstructions;
  pdas: PrivateChannelEscrowProgramPluginPdas;
  identifyInstruction: typeof identifyPrivateChannelEscrowProgramInstruction;
  parseInstruction: typeof parsePrivateChannelEscrowProgramInstruction;
};

export type PrivateChannelEscrowProgramPluginAccounts = {
  allowedMint: ReturnType<typeof getAllowedMintCodec> &
    SelfFetchFunctions<AllowedMintArgs, AllowedMint>;
  instance: ReturnType<typeof getInstanceCodec> &
    SelfFetchFunctions<InstanceArgs, Instance>;
  operator: ReturnType<typeof getOperatorCodec> &
    SelfFetchFunctions<OperatorArgs, Operator>;
};

export type PrivateChannelEscrowProgramPluginInstructions = {
  createInstance: (
    input: CreateInstanceAsyncInput,
  ) => ReturnType<typeof getCreateInstanceInstructionAsync> &
    SelfPlanAndSendFunctions;
  allowMint: (
    input: AllowMintAsyncInput,
  ) => ReturnType<typeof getAllowMintInstructionAsync> &
    SelfPlanAndSendFunctions;
  blockMint: (
    input: BlockMintAsyncInput,
  ) => ReturnType<typeof getBlockMintInstructionAsync> &
    SelfPlanAndSendFunctions;
  addOperator: (
    input: AddOperatorAsyncInput,
  ) => ReturnType<typeof getAddOperatorInstructionAsync> &
    SelfPlanAndSendFunctions;
  removeOperator: (
    input: RemoveOperatorAsyncInput,
  ) => ReturnType<typeof getRemoveOperatorInstructionAsync> &
    SelfPlanAndSendFunctions;
  setNewAdmin: (
    input: SetNewAdminAsyncInput,
  ) => ReturnType<typeof getSetNewAdminInstructionAsync> &
    SelfPlanAndSendFunctions;
  deposit: (
    input: DepositAsyncInput,
  ) => ReturnType<typeof getDepositInstructionAsync> & SelfPlanAndSendFunctions;
  releaseFunds: (
    input: ReleaseFundsAsyncInput,
  ) => ReturnType<typeof getReleaseFundsInstructionAsync> &
    SelfPlanAndSendFunctions;
  resetSmtRoot: (
    input: ResetSmtRootAsyncInput,
  ) => ReturnType<typeof getResetSmtRootInstructionAsync> &
    SelfPlanAndSendFunctions;
};

export type PrivateChannelEscrowProgramPluginPdas = {
  instance: typeof findInstancePda;
  allowedMint: typeof findAllowedMintPda;
  operator: typeof findOperatorPda;
  eventAuthority: typeof findEventAuthorityPda;
};

export type PrivateChannelEscrowProgramPluginRequirements = ClientWithRpc<
  GetAccountInfoApi & GetMultipleAccountsApi
> &
  ClientWithTransactionPlanning &
  ClientWithTransactionSending;

export function privateChannelEscrowProgramProgram() {
  return <T extends PrivateChannelEscrowProgramPluginRequirements>(
    client: T,
  ): ExtendedClient<
    T,
    { privateChannelEscrowProgram: PrivateChannelEscrowProgramPlugin }
  > => {
    return extendClient(client, {
      privateChannelEscrowProgram: <PrivateChannelEscrowProgramPlugin>{
        accounts: {
          allowedMint: addSelfFetchFunctions(client, getAllowedMintCodec()),
          instance: addSelfFetchFunctions(client, getInstanceCodec()),
          operator: addSelfFetchFunctions(client, getOperatorCodec()),
        },
        instructions: {
          createInstance: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getCreateInstanceInstructionAsync(input),
            ),
          allowMint: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getAllowMintInstructionAsync(input),
            ),
          blockMint: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getBlockMintInstructionAsync(input),
            ),
          addOperator: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getAddOperatorInstructionAsync(input),
            ),
          removeOperator: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getRemoveOperatorInstructionAsync(input),
            ),
          setNewAdmin: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getSetNewAdminInstructionAsync(input),
            ),
          deposit: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getDepositInstructionAsync(input),
            ),
          releaseFunds: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getReleaseFundsInstructionAsync(input),
            ),
          resetSmtRoot: (input) =>
            addSelfPlanAndSendFunctions(
              client,
              getResetSmtRootInstructionAsync(input),
            ),
        },
        pdas: {
          instance: findInstancePda,
          allowedMint: findAllowedMintPda,
          operator: findOperatorPda,
          eventAuthority: findEventAuthorityPda,
        },
        identifyInstruction: identifyPrivateChannelEscrowProgramInstruction,
        parseInstruction: parsePrivateChannelEscrowProgramInstruction,
      },
    });
  };
}
