/**
 * 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 { combineCodec, fixDecoderSize, fixEncoderSize, getBooleanDecoder, getBooleanEncoder, getBytesDecoder, getBytesEncoder, getStructDecoder, getStructEncoder, getU128Decoder, getU128Encoder, getU64Decoder, getU64Encoder, transformEncoder, type AccountMeta, type AccountSignerMeta, type Address, type FixedSizeCodec, type FixedSizeDecoder, type FixedSizeEncoder, type Instruction, type InstructionWithAccounts, type InstructionWithData, type ReadonlyAccount, type ReadonlySignerAccount, type ReadonlyUint8Array, type TransactionSigner, type WritableAccount } from '@solana/kit';
import { AMM_V3_PROGRAM_ADDRESS } from '../programs';
import { getAccountMetaFactory, type ResolvedAccount } from '../shared';

export const SWAP_V2_DISCRIMINATOR = new Uint8Array([43, 4, 237, 11, 26, 201, 30, 98]);

export function getSwapV2DiscriminatorBytes() { return fixEncoderSize(getBytesEncoder(), 8).encode(SWAP_V2_DISCRIMINATOR); }

export type SwapV2Instruction<TProgram extends string = typeof AMM_V3_PROGRAM_ADDRESS, TAccountPayer extends string | AccountMeta<string> = string, TAccountAmmConfig extends string | AccountMeta<string> = string, TAccountPoolState extends string | AccountMeta<string> = string, TAccountInputTokenAccount extends string | AccountMeta<string> = string, TAccountOutputTokenAccount extends string | AccountMeta<string> = string, TAccountInputVault extends string | AccountMeta<string> = string, TAccountOutputVault extends string | AccountMeta<string> = string, TAccountObservationState extends string | AccountMeta<string> = string, TAccountTokenProgram extends string | AccountMeta<string> = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", TAccountTokenProgram2022 extends string | AccountMeta<string> = string, TAccountMemoProgram extends string | AccountMeta<string> = string, TAccountInputVaultMint extends string | AccountMeta<string> = string, TAccountOutputVaultMint extends string | AccountMeta<string> = string, TRemainingAccounts extends readonly AccountMeta<string>[] = []> =
Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array> & InstructionWithAccounts<[TAccountPayer extends string ? ReadonlySignerAccount<TAccountPayer> & AccountSignerMeta<TAccountPayer> : TAccountPayer, TAccountAmmConfig extends string ? ReadonlyAccount<TAccountAmmConfig> : TAccountAmmConfig, TAccountPoolState extends string ? WritableAccount<TAccountPoolState> : TAccountPoolState, TAccountInputTokenAccount extends string ? WritableAccount<TAccountInputTokenAccount> : TAccountInputTokenAccount, TAccountOutputTokenAccount extends string ? WritableAccount<TAccountOutputTokenAccount> : TAccountOutputTokenAccount, TAccountInputVault extends string ? WritableAccount<TAccountInputVault> : TAccountInputVault, TAccountOutputVault extends string ? WritableAccount<TAccountOutputVault> : TAccountOutputVault, TAccountObservationState extends string ? WritableAccount<TAccountObservationState> : TAccountObservationState, TAccountTokenProgram extends string ? ReadonlyAccount<TAccountTokenProgram> : TAccountTokenProgram, TAccountTokenProgram2022 extends string ? ReadonlyAccount<TAccountTokenProgram2022> : TAccountTokenProgram2022, TAccountMemoProgram extends string ? ReadonlyAccount<TAccountMemoProgram> : TAccountMemoProgram, TAccountInputVaultMint extends string ? ReadonlyAccount<TAccountInputVaultMint> : TAccountInputVaultMint, TAccountOutputVaultMint extends string ? ReadonlyAccount<TAccountOutputVaultMint> : TAccountOutputVaultMint, ...TRemainingAccounts]>;

export type SwapV2InstructionData = { discriminator: ReadonlyUint8Array; amount: bigint; otherAmountThreshold: bigint; sqrtPriceLimitX64: bigint; isBaseInput: boolean;  };

export type SwapV2InstructionDataArgs = { amount: number | bigint; otherAmountThreshold: number | bigint; sqrtPriceLimitX64: number | bigint; isBaseInput: boolean;  };

export function getSwapV2InstructionDataEncoder(): FixedSizeEncoder<SwapV2InstructionDataArgs> {
    return transformEncoder(getStructEncoder([['discriminator', fixEncoderSize(getBytesEncoder(), 8)], ['amount', getU64Encoder()], ['otherAmountThreshold', getU64Encoder()], ['sqrtPriceLimitX64', getU128Encoder()], ['isBaseInput', getBooleanEncoder()]]), (value) => ({ ...value, discriminator: SWAP_V2_DISCRIMINATOR }));
}

export function getSwapV2InstructionDataDecoder(): FixedSizeDecoder<SwapV2InstructionData> {
    return getStructDecoder([['discriminator', fixDecoderSize(getBytesDecoder(), 8)], ['amount', getU64Decoder()], ['otherAmountThreshold', getU64Decoder()], ['sqrtPriceLimitX64', getU128Decoder()], ['isBaseInput', getBooleanDecoder()]]);
}

export function getSwapV2InstructionDataCodec(): FixedSizeCodec<SwapV2InstructionDataArgs, SwapV2InstructionData> {
    return combineCodec(getSwapV2InstructionDataEncoder(), getSwapV2InstructionDataDecoder());
}

export type SwapV2Input<TAccountPayer extends string = string, TAccountAmmConfig extends string = string, TAccountPoolState extends string = string, TAccountInputTokenAccount extends string = string, TAccountOutputTokenAccount extends string = string, TAccountInputVault extends string = string, TAccountOutputVault extends string = string, TAccountObservationState extends string = string, TAccountTokenProgram extends string = string, TAccountTokenProgram2022 extends string = string, TAccountMemoProgram extends string = string, TAccountInputVaultMint extends string = string, TAccountOutputVaultMint extends string = string> =  {
  payer: TransactionSigner<TAccountPayer>;
ammConfig: Address<TAccountAmmConfig>;
poolState: Address<TAccountPoolState>;
inputTokenAccount: Address<TAccountInputTokenAccount>;
outputTokenAccount: Address<TAccountOutputTokenAccount>;
inputVault: Address<TAccountInputVault>;
outputVault: Address<TAccountOutputVault>;
observationState: Address<TAccountObservationState>;
tokenProgram?: Address<TAccountTokenProgram>;
tokenProgram2022: Address<TAccountTokenProgram2022>;
memoProgram: Address<TAccountMemoProgram>;
inputVaultMint: Address<TAccountInputVaultMint>;
outputVaultMint: Address<TAccountOutputVaultMint>;
amount: SwapV2InstructionDataArgs["amount"];
otherAmountThreshold: SwapV2InstructionDataArgs["otherAmountThreshold"];
sqrtPriceLimitX64: SwapV2InstructionDataArgs["sqrtPriceLimitX64"];
isBaseInput: SwapV2InstructionDataArgs["isBaseInput"];
}

export function getSwapV2Instruction<TAccountPayer extends string, TAccountAmmConfig extends string, TAccountPoolState extends string, TAccountInputTokenAccount extends string, TAccountOutputTokenAccount extends string, TAccountInputVault extends string, TAccountOutputVault extends string, TAccountObservationState extends string, TAccountTokenProgram extends string, TAccountTokenProgram2022 extends string, TAccountMemoProgram extends string, TAccountInputVaultMint extends string, TAccountOutputVaultMint extends string, TProgramAddress extends Address = typeof AMM_V3_PROGRAM_ADDRESS>(input: SwapV2Input<TAccountPayer, TAccountAmmConfig, TAccountPoolState, TAccountInputTokenAccount, TAccountOutputTokenAccount, TAccountInputVault, TAccountOutputVault, TAccountObservationState, TAccountTokenProgram, TAccountTokenProgram2022, TAccountMemoProgram, TAccountInputVaultMint, TAccountOutputVaultMint>, config?: { programAddress?: TProgramAddress } ): SwapV2Instruction<TProgramAddress, TAccountPayer, TAccountAmmConfig, TAccountPoolState, TAccountInputTokenAccount, TAccountOutputTokenAccount, TAccountInputVault, TAccountOutputVault, TAccountObservationState, TAccountTokenProgram, TAccountTokenProgram2022, TAccountMemoProgram, TAccountInputVaultMint, TAccountOutputVaultMint> {
  // Program address.
const programAddress = config?.programAddress ?? AMM_V3_PROGRAM_ADDRESS;

 // Original accounts.
const originalAccounts = { payer: { value: input.payer ?? null, isWritable: false }, ammConfig: { value: input.ammConfig ?? null, isWritable: false }, poolState: { value: input.poolState ?? null, isWritable: true }, inputTokenAccount: { value: input.inputTokenAccount ?? null, isWritable: true }, outputTokenAccount: { value: input.outputTokenAccount ?? null, isWritable: true }, inputVault: { value: input.inputVault ?? null, isWritable: true }, outputVault: { value: input.outputVault ?? null, isWritable: true }, observationState: { value: input.observationState ?? null, isWritable: true }, tokenProgram: { value: input.tokenProgram ?? null, isWritable: false }, tokenProgram2022: { value: input.tokenProgram2022 ?? null, isWritable: false }, memoProgram: { value: input.memoProgram ?? null, isWritable: false }, inputVaultMint: { value: input.inputVaultMint ?? null, isWritable: false }, outputVaultMint: { value: input.outputVaultMint ?? null, isWritable: false } }
const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedAccount>;


// Original args.
const args = { ...input,  };


// Resolve default values.
if (!accounts.tokenProgram.value) {
accounts.tokenProgram.value = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' as Address<'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'>;
}

const getAccountMeta = getAccountMetaFactory(programAddress, 'programId');
return Object.freeze({ accounts: [getAccountMeta(accounts.payer), getAccountMeta(accounts.ammConfig), getAccountMeta(accounts.poolState), getAccountMeta(accounts.inputTokenAccount), getAccountMeta(accounts.outputTokenAccount), getAccountMeta(accounts.inputVault), getAccountMeta(accounts.outputVault), getAccountMeta(accounts.observationState), getAccountMeta(accounts.tokenProgram), getAccountMeta(accounts.tokenProgram2022), getAccountMeta(accounts.memoProgram), getAccountMeta(accounts.inputVaultMint), getAccountMeta(accounts.outputVaultMint)], data: getSwapV2InstructionDataEncoder().encode(args as SwapV2InstructionDataArgs), programAddress } as SwapV2Instruction<TProgramAddress, TAccountPayer, TAccountAmmConfig, TAccountPoolState, TAccountInputTokenAccount, TAccountOutputTokenAccount, TAccountInputVault, TAccountOutputVault, TAccountObservationState, TAccountTokenProgram, TAccountTokenProgram2022, TAccountMemoProgram, TAccountInputVaultMint, TAccountOutputVaultMint>);
}

export type ParsedSwapV2Instruction<TProgram extends string = typeof AMM_V3_PROGRAM_ADDRESS, TAccountMetas extends readonly AccountMeta[] = readonly AccountMeta[]> = { programAddress: Address<TProgram>;
accounts: {
payer: TAccountMetas[0];
ammConfig: TAccountMetas[1];
poolState: TAccountMetas[2];
inputTokenAccount: TAccountMetas[3];
outputTokenAccount: TAccountMetas[4];
inputVault: TAccountMetas[5];
outputVault: TAccountMetas[6];
observationState: TAccountMetas[7];
tokenProgram: TAccountMetas[8];
tokenProgram2022: TAccountMetas[9];
memoProgram: TAccountMetas[10];
inputVaultMint: TAccountMetas[11];
outputVaultMint: TAccountMetas[12];
};
data: SwapV2InstructionData; };

export function parseSwapV2Instruction<TProgram extends string, TAccountMetas extends readonly AccountMeta[]>(instruction: Instruction<TProgram> & InstructionWithAccounts<TAccountMetas> & InstructionWithData<ReadonlyUint8Array>): ParsedSwapV2Instruction<TProgram, TAccountMetas> {
  if (instruction.accounts.length < 13) {
  // TODO: Coded error.
  throw new Error('Not enough accounts');
}
let accountIndex = 0;
const getNextAccount = () => {
  const accountMeta = (instruction.accounts as TAccountMetas)[accountIndex]!;
  accountIndex += 1;
  return accountMeta;
}
  return { programAddress: instruction.programAddress, accounts: { payer: getNextAccount(), ammConfig: getNextAccount(), poolState: getNextAccount(), inputTokenAccount: getNextAccount(), outputTokenAccount: getNextAccount(), inputVault: getNextAccount(), outputVault: getNextAccount(), observationState: getNextAccount(), tokenProgram: getNextAccount(), tokenProgram2022: getNextAccount(), memoProgram: getNextAccount(), inputVaultMint: getNextAccount(), outputVaultMint: getNextAccount() }, data: getSwapV2InstructionDataDecoder().decode(instruction.data) };
}