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

import { Ok, Err, Some, None, type Result, type Option, type ValidationError, type JsonValue, type BoundaryError, type ServiceBinding, callService, boundaryError } from "../../runtime.js";

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

import * as commerce_payment from "../commerce-payment/handlers.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: { env: { COMMERCE_PAYMENT: ServiceBinding } }): Promise<Result<void, OrderError>> {
    const auth = await callService(deps.env.COMMERCE_PAYMENT, "authorise", commerce_payment.serialise_Money(total), commerce_payment.deserialise_Result_AuthId_PaymentError, "commerce.orders");
    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 function serialise_OrderError(value: OrderError): JsonValue {
  switch (value.tag) {
    case "PaymentDeclined":
      return { kind: "PaymentDeclined" };
    case "PaymentInsufficientFunds":
      return { kind: "PaymentInsufficientFunds" };
    case "PaymentInfrastructureError":
      return { kind: "PaymentInfrastructureError" };
  }
}

export function deserialise_OrderError(json: JsonValue, path: string = "$"): Result<OrderError, BoundaryError> {
  if (typeof json !== "object" || json === null || Array.isArray(json)) {
    return Err({ kind: "StructuralMismatch", path, expected: "object", actual: typeof json });
  }
  const obj = json as { [k: string]: JsonValue };
  const kind = obj["kind"];
  switch (kind) {
    case "PaymentDeclined":
      return Ok({ tag: "PaymentDeclined" } as OrderError);
    case "PaymentInsufficientFunds":
      return Ok({ tag: "PaymentInsufficientFunds" } as OrderError);
    case "PaymentInfrastructureError":
      return Ok({ tag: "PaymentInfrastructureError" } as OrderError);
    default:
      return Err({ kind: "StructuralMismatch", path, expected: "sum variant kind", actual: String(kind) });
  }
}


import { serialise_CurrencyCode, deserialise_CurrencyCode, serialise_Money, deserialise_Money } from "../../commerce/money.js";
export { serialise_CurrencyCode, deserialise_CurrencyCode, serialise_Money, deserialise_Money };

export function serialise_Result_Unit_OrderError(value: Result<void, OrderError>): JsonValue {
  if (value.tag === "Ok") return { kind: "Ok", value: null };
  return { kind: "Err", error: serialise_OrderError(value.error) };
}

export function deserialise_Result_Unit_OrderError(json: JsonValue, path: string = "$"): Result<Result<void, OrderError>, BoundaryError> {
  if (typeof json !== "object" || json === null || Array.isArray(json)) {
    return Err({ kind: "StructuralMismatch", path, expected: "object", actual: typeof json });
  }
  const obj = json as { [k: string]: JsonValue };
  if (obj["kind"] === "Ok") {
  const __v = undefined;
    return Ok(Ok(__v) as Result<void, OrderError>);
  } else if (obj["kind"] === "Err") {
  const __r_e = deserialise_OrderError(obj["error"], `${path}.error`);
  if (__r_e.tag === "Err") return __r_e;
  const __e = __r_e.value;
    return Ok(Err(__e) as Result<void, OrderError>);
  }
  return Err({ kind: "StructuralMismatch", path, expected: "Ok | Err", actual: String(obj["kind"]) });
}

