/**
 * This code was GENERATED 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 {
  assertAccountExists,
  assertAccountsExist,
  decodeAccount,
  fetchEncodedAccount,
  fetchEncodedAccounts,
  type Account,
  type EncodedAccount,
  type FetchAccountConfig,
  type FetchAccountsConfig,
  type MaybeAccount,
  type MaybeEncodedAccount,
} from '@solana/accounts';
import {
  getAddressDecoder,
  getAddressEncoder,
  type Address,
} from '@solana/addresses';
import {
  addDecoderSizePrefix,
  addEncoderSizePrefix,
  combineCodec,
  fixDecoderSize,
  fixEncoderSize,
  getBytesDecoder,
  getBytesEncoder,
  getI64Decoder,
  getI64Encoder,
  getStructDecoder,
  getStructEncoder,
  getU32Decoder,
  getU32Encoder,
  getU64Decoder,
  getU64Encoder,
  getU8Decoder,
  getU8Encoder,
  getUtf8Decoder,
  getUtf8Encoder,
  transformEncoder,
  type Codec,
  type Decoder,
  type Encoder,
  type ReadonlyUint8Array,
} from '@solana/codecs';

export const JOB_ACCOUNT_DISCRIMINATOR = new Uint8Array([
  189, 45, 123, 78, 211, 99, 167, 244,
]);

export function getJobAccountDiscriminatorBytes() {
  return fixEncoderSize(getBytesEncoder(), 8).encode(
    JOB_ACCOUNT_DISCRIMINATOR
  );
}

export type JobAccount = {
  discriminator: ReadonlyUint8Array;
  jobId: bigint;
  employer: Address;
  title: string;
  description: string;
  requirements: string[];
  budgetMin: bigint;
  budgetMax: bigint;
  paymentToken: Address;
  deadline: bigint;
  skillsNeeded: string[];
  jobType: string;
  experienceLevel: string;
  status: JobStatus;
  applicants: Address[];
  selectedApplicant: Address;
  createdAt: bigint;
  updatedAt: bigint;
  bump: number;
  reserved: ReadonlyUint8Array;
};

export type JobAccountArgs = {
  jobId: number | bigint;
  employer: Address;
  title: string;
  description: string;
  requirements: string[];
  budgetMin: number | bigint;
  budgetMax: number | bigint;
  paymentToken: Address;
  deadline: number | bigint;
  skillsNeeded: string[];
  jobType: string;
  experienceLevel: string;
  status: JobStatus;
  applicants: Address[];
  selectedApplicant: Address;
  createdAt: number | bigint;
  updatedAt: number | bigint;
  bump: number;
  reserved: ReadonlyUint8Array;
};

export enum JobStatus {
  Open = 0,
  InProgress = 1,
  Completed = 2,
  Cancelled = 3,
  Disputed = 4,
}

export function getJobAccountEncoder(): Encoder<JobAccountArgs> {
  return transformEncoder(
    getStructEncoder([
      ['discriminator', fixEncoderSize(getBytesEncoder(), 8)],
      ['jobId', getU64Encoder()],
      ['employer', getAddressEncoder()],
      ['title', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
      ['description', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
      ['requirements', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
      ['budgetMin', getU64Encoder()],
      ['budgetMax', getU64Encoder()],
      ['paymentToken', getAddressEncoder()],
      ['deadline', getI64Encoder()],
      ['skillsNeeded', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
      ['jobType', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
      ['experienceLevel', addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder())],
      ['status', getU8Encoder()],
      ['applicants', fixEncoderSize(getBytesEncoder(), 320)], // 10 applicants * 32 bytes each
      ['selectedApplicant', getAddressEncoder()],
      ['createdAt', getI64Encoder()],
      ['updatedAt', getI64Encoder()],
      ['bump', getU8Encoder()],
      ['reserved', fixEncoderSize(getBytesEncoder(), 31)],
    ]),
    (value) => ({ ...value, discriminator: JOB_ACCOUNT_DISCRIMINATOR })
  );
}

export function getJobAccountDecoder(): Decoder<JobAccount> {
  return getStructDecoder([
    ['discriminator', fixDecoderSize(getBytesDecoder(), 8)],
    ['jobId', getU64Decoder()],
    ['employer', getAddressDecoder()],
    ['title', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
    ['description', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
    ['requirements', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
    ['budgetMin', getU64Decoder()],
    ['budgetMax', getU64Decoder()],
    ['paymentToken', getAddressDecoder()],
    ['deadline', getI64Decoder()],
    ['skillsNeeded', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
    ['jobType', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
    ['experienceLevel', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],
    ['status', getU8Decoder()],
    ['applicants', fixDecoderSize(getBytesDecoder(), 320)], // 10 applicants * 32 bytes each
    ['selectedApplicant', getAddressDecoder()],
    ['createdAt', getI64Decoder()],
    ['updatedAt', getI64Decoder()],
    ['bump', getU8Decoder()],
    ['reserved', fixDecoderSize(getBytesDecoder(), 31)],
  ]);
}

export function getJobAccountCodec(): Codec<JobAccountArgs, JobAccount> {
  return combineCodec(getJobAccountEncoder(), getJobAccountDecoder());
}

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

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

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

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

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