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

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

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

import * as commerce_payment from "./payment.js";

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

/**
 * Orders context. Places orders, calling payment for authorisation.
 */

export type OrderError =
    { readonly tag: "PaymentDeclined" }
  | { readonly tag: "PaymentInsufficientFunds" }
  | { readonly tag: "PaymentInfrastructureError" };

export const OrderError = {
  PaymentDeclined: { tag: "PaymentDeclined" } as OrderError,
  PaymentInsufficientFunds: { tag: "PaymentInsufficientFunds" } as OrderError,
  PaymentInfrastructureError: { tag: "PaymentInfrastructureError" } as OrderError,
};

export const placeOrder = {
  /**
   * Place an order by authorising payment for the total amount. Maps
   * payment's error variants to orders' own OrderError shape (the
   * anti-corruption-layer pattern).
   */
  async call(total: Money, deps: { surface: { Payment: ReturnType<typeof commerce_payment.makeSurface> } }): Promise<Result<void, OrderError>> {
    const auth = await deps.surface.Payment.authorise((total as unknown as commerce_payment.Money));
    switch (auth.tag) {
      case "Ok": {
        return Ok(undefined);
      }
      case "Err": {
        const error = auth.error;
        return ((__d) => {
    switch (__d.tag) {
      case "Declined": {
        return Err(OrderError.PaymentDeclined);
      }
      case "InsufficientFunds": {
        return Err(OrderError.PaymentInsufficientFunds);
      }
      case "GatewayDown": {
        return Err(OrderError.PaymentInfrastructureError);
      }
    }
    throw new Error("non-exhaustive match");
  })(error);
      }
    }
    throw new Error("non-exhaustive match");
  },
};

export interface CommerceOrdersDeps {
  readonly surface: { Payment: ReturnType<typeof commerce_payment.makeSurface> };
}

export function makeSurface(deps: CommerceOrdersDeps) {
  return {
    async placeOrder(total: Money): Promise<Result<void, OrderError>> {
      return placeOrder.call(total, deps);
    },
  };
}

