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

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";

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

/**
 * Payment context. Authorises monetary transactions.
 */

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 class StubPayments implements Payments {
  async authorise(amount: Money): Promise<Result<AuthId, PaymentError>> {
    return (amount.minorUnits > 1000000 ? Err(PaymentError.Declined) : Ok(AuthId.unsafe("AUTH-12345678")));
  }
}

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

/**
 * Authorise a payment. The single entry point for payment authorisation
 * from other contexts.
 */
export const authorise = {
  async call(amount: Money, deps: { Payments: Payments }): Promise<Result<AuthId, PaymentError>> {
    const result = await deps.Payments.authorise(amount);
    return result;
  },
};

export function serialise_AuthId(value: AuthId): JsonValue {
  return value as unknown as string;
}

export function deserialise_AuthId(json: JsonValue, path: string = "$"): Result<AuthId, BoundaryError> {
  if (typeof json !== "string") {
    return Err({ kind: "StructuralMismatch", path, expected: "string", actual: typeof json });
  }
  const validated = (typeof (AuthId as any).of === "function")
    ? (AuthId as any).of(json)
    : Ok(json as unknown as AuthId);
  if (validated.tag === "Err") {
    return Err({ kind: "RefinementViolation", path, violation: validated.error });
  }
  return Ok(validated.value as AuthId);
}

export function serialise_PaymentError(value: PaymentError): JsonValue {
  switch (value.tag) {
    case "Declined":
      return { kind: "Declined" };
    case "InsufficientFunds":
      return { kind: "InsufficientFunds" };
    case "GatewayDown":
      return { kind: "GatewayDown" };
  }
}

export function deserialise_PaymentError(json: JsonValue, path: string = "$"): Result<PaymentError, 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 "Declined":
      return Ok({ tag: "Declined" } as PaymentError);
    case "InsufficientFunds":
      return Ok({ tag: "InsufficientFunds" } as PaymentError);
    case "GatewayDown":
      return Ok({ tag: "GatewayDown" } as PaymentError);
    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_AuthId_PaymentError(value: Result<AuthId, PaymentError>): JsonValue {
  if (value.tag === "Ok") return { kind: "Ok", value: serialise_AuthId(value.value) };
  return { kind: "Err", error: serialise_PaymentError(value.error) };
}

export function deserialise_Result_AuthId_PaymentError(json: JsonValue, path: string = "$"): Result<Result<AuthId, PaymentError>, 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 __r_v = deserialise_AuthId(obj["value"], `${path}.value`);
  if (__r_v.tag === "Err") return __r_v;
  const __v = __r_v.value;
    return Ok(Ok(__v) as Result<AuthId, PaymentError>);
  } else if (obj["kind"] === "Err") {
  const __r_e = deserialise_PaymentError(obj["error"], `${path}.error`);
  if (__r_e.tag === "Err") return __r_e;
  const __e = __r_e.value;
    return Ok(Err(__e) as Result<AuthId, PaymentError>);
  }
  return Err({ kind: "StructuralMismatch", path, expected: "Ok | Err", actual: String(obj["kind"]) });
}

