import type { Precondition } from './flow.js';

/**
 * The three concrete precondition shapes the stack exchanges today. One
 * definition serves every producer and consumer: op/materialiser declarations,
 * `rewritePreconditions`, the simulator's funding requirements (`simulate.ts`
 * aliases these as `*Requirement`), and the zap-backend approval derivation.
 *
 * Amounts accept `bigint | string`: the SDK serialises `bigint` to a decimal
 * string; the string side covers values already stringified.
 */
export type Erc20BalancePrecondition = {
  readonly type: 'Erc20Balance';
  readonly wallet: string;
  readonly token: string;
  readonly balance: bigint | string;
};

export type NativeBalancePrecondition = {
  readonly type: 'NativeBalance';
  readonly wallet: string;
  readonly balance: bigint | string;
};

export type Erc20AllowancePrecondition = {
  readonly type: 'Erc20Allowance';
  readonly owner: string;
  readonly spender: string;
  readonly token: string;
  readonly allowance: bigint | string;
};

export const erc20Balance = (
  config: Omit<Erc20BalancePrecondition, 'type'>,
): Erc20BalancePrecondition => ({ type: 'Erc20Balance', ...config });

export const nativeBalance = (
  config: Omit<NativeBalancePrecondition, 'type'>,
): NativeBalancePrecondition => ({ type: 'NativeBalance', ...config });

export const erc20Allowance = (
  config: Omit<Erc20AllowancePrecondition, 'type'>,
): Erc20AllowancePrecondition => ({ type: 'Erc20Allowance', ...config });

export const isErc20AllowancePrecondition = (
  p: Precondition,
): p is Erc20AllowancePrecondition => p.type === 'Erc20Allowance';

export const isNativeBalancePrecondition = (
  p: Precondition,
): p is NativeBalancePrecondition => p.type === 'NativeBalance';
