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

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

/**
 * A fresh `Meter` key reads a nested record of zeros: every field of a zeroable
 * record zero-initialises recursively.
 */

export type MeterId = string & { readonly __brand: "demo.meter.MeterId" };

export const MeterId = {
  of(value: string): Result<MeterId, ValidationError> {
    if (!new RegExp("^" + "[a-z0-9]{1,16}" + "$").test(value)) {
      return Err({ field: "MeterId", message: "must match /[a-z0-9]{1,16}/", value });
    }
    return Ok(value as MeterId);
  },
  unsafe(value: string): MeterId {
    return value as MeterId;
  },
};

export interface Totals {
  readonly hits: number;
  readonly bytes: number;
}

export const Totals = {
};

export type MeterError =
    { readonly tag: "Missing" };

export const MeterError = {
  Missing: { tag: "Missing" } as MeterError,
};

export interface MeterState {
  readonly totals: Totals;
  readonly active: boolean;
}

const __MeterRegistry = new StateRegistry();
function __zeroOfMeterState(): MeterState { return { totals: { hits: 0, bytes: 0 }, active: false }; }

function __rehydrateMeterState(s: MeterState): void {
  { const __r = deserialise_Totals((s.totals as unknown as JsonValue), "totals"); if (__r.tag === "Err") throw rehydrationViolation("Meter", __r.error); }
  { const __r = ((__v) => typeof __v === "boolean" ? Ok(__v) : Err({ kind: "StructuralMismatch", path: "active", expected: "boolean", actual: typeof __v } as BoundaryError))((s.active as unknown as JsonValue)); if (__r.tag === "Err") throw rehydrationViolation("Meter", __r.error); }
}

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

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

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

  async hits(deps: {}): Promise<Result<number, MeterError>> {
    const __state = await this.loadState();
    return Ok(__state.totals.hits);
  }

}

export function __makeMeter(key: MeterId, env?: { METER?: DurableObjectNamespace }): Meter {
  return makeAgent(__MeterRegistry, env?.METER, key, (state) => new Meter(state));
}

export const hits = {
  async call(id: MeterId, deps: {}): Promise<Result<number, MeterError>> {
    const meter = __makeMeter(id);
    const total = await meter.hits(deps);
    return total;
  },
};

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

export interface DemoMeterDeps {
}

export function makeSurface(deps: DemoMeterDeps) {
  return {
    async hits(id: MeterId): Promise<Result<number, MeterError>> {
      return hits.call(id, deps);
    },
  };
}

export function serialise_Totals(value: Totals): JsonValue {
  return {
    hits: value.hits as JsonValue,
    bytes: value.bytes as JsonValue,
  };
}

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


