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

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

import * as shop_payment from "../shop-payment/handlers.js";

export type OrderError =
    { readonly tag: "Rejected" };

export const OrderError = {
  Rejected: { tag: "Rejected" } as OrderError,
};

export interface LedgerState {
  readonly placed: number;
}

const __LedgerRegistry = new StateRegistry();
function __zeroOfLedgerState(): LedgerState { return { placed: 0 }; }

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

  private async loadState(): Promise<LedgerState> {
    const stored = await this.state.storage.get<LedgerState>("state");
    return stored ?? __zeroOfLedgerState();
  }

  private async commitState(s: LedgerState): Promise<void> {
    await this.state.storage.put("state", s);
  }

  async tally(deps: {}): Promise<Result<number, OrderError>> {
    const currentState = await this.loadState();
    const n = currentState.placed + 1;
    await this.commitState({ ...currentState, placed: n });
    return Ok(n);
  }

  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    if (url.pathname.startsWith("/_bynk/agent/")) {
      const methodName = url.pathname.slice("/_bynk/agent/".length);
      const { args, deps } = (await request.json()) as { args: unknown[]; deps: unknown };
      const result = await (this as any)[methodName](...args, deps);
      return new Response(JSON.stringify(result), { headers: { "content-type": "application/json" } });
    }
    return new Response("Not Found", { status: 404 });
  }

}

export function __makeLedger(key: string, env?: { LEDGER?: DurableObjectNamespace }): Ledger {
  return makeAgent(__LedgerRegistry, env?.LEDGER, key, (state) => new Ledger(state));
}

export const place = {
  async call(id: string, cents: number, deps: { env: { SHOP_PAYMENT: ServiceBinding; LEDGER: DurableObjectNamespace } }): Promise<Result<number, OrderError>> {
    const a = await callService(deps.env.SHOP_PAYMENT, "authorise", cents as JsonValue, shop_payment.deserialise_Result_Int_PayError, "shop.orders");
    switch (a.tag) {
      case "Ok": {
        const ledger = __makeLedger(id, deps.env);
        const count = await ledger.tally(deps);
        return count;
      }
      case "Err": {
        return Err(OrderError.Rejected);
      }
    }
    throw new Error("non-exhaustive match");
  },
};

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

export function serialise_OrderError(value: OrderError): JsonValue {
  switch (value.tag) {
    case "Rejected":
      return { kind: "Rejected" };
  }
}

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 "Rejected":
      return Ok({ tag: "Rejected" } as OrderError);
    default:
      return Err({ kind: "StructuralMismatch", path, expected: "sum variant kind", actual: String(kind) });
  }
}


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

export function deserialise_Result_Int_OrderError(json: JsonValue, path: string = "$"): Result<Result<number, 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") {
  if (typeof obj["value"] !== "number") {
    return Err({ kind: "StructuralMismatch", path: `${path}.value`, expected: "number", actual: typeof obj["value"] });
  }
  if (!Number.isInteger(obj["value"])) {
    return Err({ kind: "StructuralMismatch", path: `${path}.value`, expected: "integer", actual: String(obj["value"]) });
  }
  const __v = obj["value"];
    return Ok(Ok(__v) as Result<number, 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<number, OrderError>);
  }
  return Err({ kind: "StructuralMismatch", path, expected: "Ok | Err", actual: String(obj["kind"]) });
}

