/**
 * 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 {
  type Account,
  type Address,
  assertAccountExists,
  assertAccountsExist,
  type Codec,
  combineCodec,
  type Decoder,
  decodeAccount,
  type EncodedAccount,
  type Encoder,
  type FetchAccountConfig,
  type FetchAccountsConfig,
  fetchEncodedAccount,
  fetchEncodedAccounts,
  getAddressDecoder,
  getAddressEncoder,
  getStructDecoder,
  getStructEncoder,
  getU8Decoder,
  getU8Encoder,
  getU64Decoder,
  getU64Encoder,
  type MaybeAccount,
  type MaybeEncodedAccount,
} from '@solana/kit';
import { findConfigPda } from '../pdas';

export const CONFIG_DISCRIMINATOR = 0;

export function getConfigDiscriminatorBytes() {
  return getU8Encoder().encode(CONFIG_DISCRIMINATOR);
}

export type Config = {
  discriminator: number;
  authority: Address;
  blockedWalletsCount: bigint;
};

export type ConfigArgs = {
  discriminator: number;
  authority: Address;
  blockedWalletsCount: number | bigint;
};

export function getConfigEncoder(): Encoder<ConfigArgs> {
  return getStructEncoder([
    ['discriminator', getU8Encoder()],
    ['authority', getAddressEncoder()],
    ['blockedWalletsCount', getU64Encoder()],
  ]);
}

export function getConfigDecoder(): Decoder<Config> {
  return getStructDecoder([
    ['discriminator', getU8Decoder()],
    ['authority', getAddressDecoder()],
    ['blockedWalletsCount', getU64Decoder()],
  ]);
}

export function getConfigCodec(): Codec<ConfigArgs, Config> {
  return combineCodec(getConfigEncoder(), getConfigDecoder());
}

export function decodeConfig<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): Account<Config, TAddress>;
export function decodeConfig<TAddress extends string = string>(encodedAccount: MaybeEncodedAccount<TAddress>): MaybeAccount<Config, TAddress>;
export function decodeConfig<TAddress extends string = string>(
  encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>,
): Account<Config, TAddress> | MaybeAccount<Config, TAddress> {
  return decodeAccount(encodedAccount as MaybeEncodedAccount<TAddress>, getConfigDecoder());
}

export async function fetchConfig<TAddress extends string = string>(
  rpc: Parameters<typeof fetchEncodedAccount>[0],
  address: Address<TAddress>,
  config?: FetchAccountConfig,
): Promise<Account<Config, TAddress>> {
  const maybeAccount = await fetchMaybeConfig(rpc, address, config);
  assertAccountExists(maybeAccount);
  return maybeAccount;
}

export async function fetchMaybeConfig<TAddress extends string = string>(
  rpc: Parameters<typeof fetchEncodedAccount>[0],
  address: Address<TAddress>,
  config?: FetchAccountConfig,
): Promise<MaybeAccount<Config, TAddress>> {
  const maybeAccount = await fetchEncodedAccount(rpc, address, config);
  return decodeConfig(maybeAccount);
}

export async function fetchAllConfig(
  rpc: Parameters<typeof fetchEncodedAccounts>[0],
  addresses: Array<Address>,
  config?: FetchAccountsConfig,
): Promise<Account<Config>[]> {
  const maybeAccounts = await fetchAllMaybeConfig(rpc, addresses, config);
  assertAccountsExist(maybeAccounts);
  return maybeAccounts;
}

export async function fetchAllMaybeConfig(
  rpc: Parameters<typeof fetchEncodedAccounts>[0],
  addresses: Array<Address>,
  config?: FetchAccountsConfig,
): Promise<MaybeAccount<Config>[]> {
  const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
  return maybeAccounts.map((maybeAccount) => decodeConfig(maybeAccount));
}

export function getConfigSize(): number {
  return 41;
}

export async function fetchConfigFromSeeds(
  rpc: Parameters<typeof fetchEncodedAccount>[0],
  config: FetchAccountConfig & { programAddress?: Address } = {},
): Promise<Account<Config>> {
  const maybeAccount = await fetchMaybeConfigFromSeeds(rpc, config);
  assertAccountExists(maybeAccount);
  return maybeAccount;
}

export async function fetchMaybeConfigFromSeeds(
  rpc: Parameters<typeof fetchEncodedAccount>[0],
  config: FetchAccountConfig & { programAddress?: Address } = {},
): Promise<MaybeAccount<Config>> {
  const { programAddress, ...fetchConfig } = config;
  const [address] = await findConfigPda({ programAddress });
  return await fetchMaybeConfig(rpc, address, fetchConfig);
}
