// Generated by bynkc — do not edit by hand.
// context commerce.payment

import { Ok, Err, Some, None, type Result, type Option, type ValidationError } from "../runtime.js";

import { Money as __CommonsMoney } from "./money.js";

export type Money = __CommonsMoney & { readonly __ctxBrand: "commerce.payment" };

/**
 * Payment context. Authorises monetary transactions via a Payments capability.
 */

export type AuthId = string & { readonly __brand: "commerce.payment.AuthId" };

export const AuthId = {
  of(value: string): Result<AuthId, ValidationError> {
    if (!new RegExp("^" + "AUTH-[0-9]{8}" + "$").test(value)) {
      return Err({ field: "AuthId", message: "must match /AUTH-[0-9]{8}/", value });
    }
    return Ok(value as AuthId);
  },
  unsafe(value: string): AuthId {
    return value as AuthId;
  },
};

export type PaymentError =
    { readonly tag: "Declined" }
  | { readonly tag: "InsufficientFunds" }
  | { readonly tag: "GatewayDown" };

export const PaymentError = {
  Declined: { tag: "Declined" } as PaymentError,
  InsufficientFunds: { tag: "InsufficientFunds" } as PaymentError,
  GatewayDown: { tag: "GatewayDown" } as PaymentError,
};

export interface Payments {
  authorise(amount: Money): Promise<Result<AuthId, PaymentError>>;
}

export const PaymentsToken: unique symbol = Symbol("Payments");

export interface Logger {
  log(message: string): Promise<void>;
}

export const LoggerToken: unique symbol = Symbol("Logger");

export class StubPayments implements Payments {
  async authorise(amount: Money): Promise<Result<AuthId, PaymentError>> {
    return Err(PaymentError.Declined);
  }
}

export const StubPaymentsProvider = { token: PaymentsToken, factory: () => new StubPayments() };

export class ConsoleLogger implements Logger {
  async log(message: string): Promise<void> {
    return undefined;
  }
}

export const ConsoleLoggerProvider = { token: LoggerToken, factory: () => new ConsoleLogger() };

export const authorise = {
  async call(amount: Money, deps: { Payments: Payments; Logger: Logger }): Promise<Result<AuthId, PaymentError>> {
    const __r0 = await deps.Logger.log("Authorising payment");
    const result = await deps.Payments.authorise(amount);
    return result;
  },
};

export interface CommercePaymentDeps {
  readonly Payments: Payments;
  readonly Logger: Logger;
}

export function makeSurface(deps: CommercePaymentDeps) {
  return {
    async authorise(amount: Money): Promise<Result<AuthId, PaymentError>> {
      return authorise.call(amount, deps);
    },
  };
}

