// Generated by bynkc — do not edit by hand.
// context demo.order

import { Ok, Err, Some, None, type Result, type Option, type ValidationError, type DurableObjectState, type DurableObjectNamespace, StateRegistry, makeAgent, invariantViolation, rehydrationViolation, type JsonValue, type BoundaryError } from "../runtime.js";

export type AuthId = string & { readonly __brand: "demo.order.AuthId" };

export const AuthId = {
  of(value: string): Result<AuthId, ValidationError> {
    if (!(value.length > 0)) {
      return Err({ field: "AuthId", message: "must be non-empty", value });
    }
    return Ok(value as AuthId);
  },
  unsafe(value: string): AuthId {
    return value as AuthId;
  },
};

export type OrderStatus =
    { readonly tag: "Pending" }
  | { readonly tag: "Paid" };

export const OrderStatus = {
  Pending: { tag: "Pending" } as OrderStatus,
  Paid: { tag: "Paid" } as OrderStatus,
};

export interface OrderState {
  readonly status: OrderStatus;
  readonly paymentRef: Option<AuthId>;
}

const __OrderRegistry = new StateRegistry();
function __zeroOfOrderState(): OrderState { return { status: OrderStatus.Pending, paymentRef: None }; }

function __rehydrateOrderState(s: OrderState): void {
  { const __r = deserialise_OrderStatus((s.status as unknown as JsonValue), "status"); if (__r.tag === "Err") throw rehydrationViolation("Order", __r.error); }
  { const __r = deserialise_Option_AuthId((s.paymentRef as unknown as JsonValue), "paymentRef"); if (__r.tag === "Err") throw rehydrationViolation("Order", __r.error); }
}

export class Order {
  state: DurableObjectState;
  constructor(state: DurableObjectState) {
    this.state = state;
  }

  private async loadState(): Promise<OrderState> {
    const stored = await this.state.storage.get<OrderState>("state");
    if (stored === undefined) return __zeroOfOrderState();
    const __merged = { ...__zeroOfOrderState(), ...stored };
    __rehydrateOrderState(__merged);
    return __merged;
  }

  private async commitState(s: OrderState): Promise<void> {
    if (!((!(s.status === OrderStatus.Paid) || (s.paymentRef.tag === "Some")))) {
      console.error("InvariantViolation Order.paid_has_payment_ref", { agent: "Order", invariant: "paid_has_payment_ref" });
      throw invariantViolation("Order", "paid_has_payment_ref");
    }
    await this.state.storage.put("state", s);
  }

  async pay(ref: AuthId, deps: {}): Promise<void> {
    const __state = { ...(await this.loadState()) };
    const __result = await (async () => {
      __state.status = OrderStatus.Paid;
      __state.paymentRef = Some(ref);
      return undefined;
    })();
    await this.commitState(__state);
    return __result;
  }

}

export function __makeOrder(key: string, env?: { ORDER?: DurableObjectNamespace }): Order {
  return makeAgent(__OrderRegistry, env?.ORDER, key, (state) => new Order(state));
}

export function __resetAgents(): void {
  __OrderRegistry.reset();
}

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_OrderStatus(value: OrderStatus): JsonValue {
  switch (value.tag) {
    case "Pending":
      return { kind: "Pending" };
    case "Paid":
      return { kind: "Paid" };
  }
}

export function deserialise_OrderStatus(json: JsonValue, path: string = "$"): Result<OrderStatus, 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 "Pending":
      return Ok({ tag: "Pending" } as OrderStatus);
    case "Paid":
      return Ok({ tag: "Paid" } as OrderStatus);
    default:
      return Err({ kind: "StructuralMismatch", path, expected: "sum variant kind", actual: String(kind) });
  }
}


export function serialise_Option_AuthId(value: Option<AuthId>): JsonValue {
  if (value.tag === "Some") return { kind: "Some", value: serialise_AuthId(value.value) };
  return { kind: "None" };
}

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

