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

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

export interface ReserveEvent {
  readonly sku: string;
  readonly qty: number;
}

export const ReserveEvent = {
};

export interface Clock {
  now(): Promise<number>;
}

export const ClockToken: unique symbol = Symbol("Clock");

export class SystemClock implements Clock {
  async now(): Promise<number> {
    return 0;
  }
}

export const SystemClockProvider = { token: ClockToken, factory: () => new SystemClock() };

export interface InventoryState {
  readonly history: Array<{ t: number; v: ReserveEvent }>;
}

const __InventoryRegistry = new StateRegistry();
function __zeroOfInventoryState(): InventoryState { return { history: [] }; }

function __rehydrateInventoryState(s: InventoryState): void {
  for (const __e of s.history) { const __r = deserialise_ReserveEvent((__e.v as unknown as JsonValue), "history"); if (__r.tag === "Err") throw rehydrationViolation("Inventory", __r.error); }
}

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

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

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

  async reserve(sku: string, qty: number, deps: { Clock: Clock }): Promise<void> {
    const __state = { ...(await this.loadState()) };
    const __result = await (async () => {
      const __r0 = await (async () => { const __now = await deps.Clock.now(); __state.history.push({ t: __now, v: { sku, qty } }); for (let __i = __state.history.length - 1; __i >= 0; __i--) { if (__state.history[__i].t < __now - 2592000000) __state.history.splice(__i, 1); } return undefined; })();
      return undefined;
    })();
    await this.commitState(__state);
    return __result;
  }

  async recentSkus(n: number, deps: {}): Promise<readonly string[]> {
    const __state = await this.loadState();
    return ((() => ((() => __state.history.slice(Math.max(0, __state.history.length - Math.max(0, n))).reverse().map((__e) => __e.v)))().map((__x) => ((e) => e.sku)(__x))))();
  }

  async countSince(t: number, deps: {}): Promise<number> {
    const __state = await this.loadState();
    return ((() => __state.history.filter((__e) => __e.t >= (t)).map((__e) => __e.v)))().length;
  }

}

export function __makeInventory(key: string, env?: { INVENTORY?: DurableObjectNamespace }): Inventory {
  return makeAgent(__InventoryRegistry, env?.INVENTORY, key, (state) => new Inventory(state));
}

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

export function serialise_ReserveEvent(value: ReserveEvent): JsonValue {
  return {
    sku: value.sku as JsonValue,
    qty: value.qty as JsonValue,
  };
}

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


