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

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 `Slot` key must read `value == None`: Option state zero-initialises.
 */

export type Label = string & { readonly __brand: "demo.slot.Label" };

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

export type SlotError =
    { readonly tag: "Empty" };

export const SlotError = {
  Empty: { tag: "Empty" } as SlotError,
};

export interface SlotState {
  readonly value: Option<number>;
}

const __SlotRegistry = new StateRegistry();
function __zeroOfSlotState(): SlotState { return { value: None }; }

function __rehydrateSlotState(s: SlotState): void {
  { const __r = deserialise_Option_Int((s.value as unknown as JsonValue), "value"); if (__r.tag === "Err") throw rehydrationViolation("Slot", __r.error); }
}

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

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

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

  async resolve(deps: {}): Promise<Result<number, SlotError>> {
    const __state = await this.loadState();
    switch (__state.value.tag) {
      case "Some": {
        const v = __state.value.value;
        return Ok(v);
      }
      case "None": {
        return Err(SlotError.Empty);
      }
    }
    throw new Error("non-exhaustive match");
  }

}

export function __makeSlot(key: Label, env?: { SLOT?: DurableObjectNamespace }): Slot {
  return makeAgent(__SlotRegistry, env?.SLOT, key, (state) => new Slot(state));
}

export const resolve = {
  async call(id: Label, deps: {}): Promise<Result<number, SlotError>> {
    const slot = __makeSlot(id);
    const outcome = await slot.resolve(deps);
    return outcome;
  },
};

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

export interface DemoSlotDeps {
}

export function makeSurface(deps: DemoSlotDeps) {
  return {
    async resolve(id: Label): Promise<Result<number, SlotError>> {
      return resolve.call(id, deps);
    },
  };
}

export function serialise_Option_Int(value: Option<number>): JsonValue {
  if (value.tag === "Some") return { kind: "Some", value: value.value as JsonValue };
  return { kind: "None" };
}

export function deserialise_Option_Int(json: JsonValue, path: string = "$"): Result<Option<number>, 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") {
  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(Some(__v) as Option<number>);
  } else if (obj["kind"] === "None") {
    return Ok(None as Option<number>);
  }
  return Err({ kind: "StructuralMismatch", path, expected: "Some | None", actual: String(obj["kind"]) });
}

