// Generated by bynkc — do not edit by hand.
// context shortener.analytics

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

import { ShortCode as __CommonsShortCode } from "./core.js";

export type ShortCode = __CommonsShortCode & { readonly __ctxBrand: "shortener.analytics" };
export const ShortCode = {
  of(value: string): Result<ShortCode, ValidationError> { return __CommonsShortCode.of(value) as unknown as Result<ShortCode, ValidationError>; },
  unsafe(value: string): ShortCode { return __CommonsShortCode.unsafe(value) as unknown as ShortCode; },
};

/**
 * Analytics context. Tracks how many times each short code has been resolved.
 *
 * Exposes two services — `record` and `count` — callable from other contexts.
 * The per-code hit state lives in a `Hits` agent: one instance per short code,
 * keyed by the code itself.
 */

export type AnalyticsError =
    { readonly tag: "NotTracked" };

export const AnalyticsError = {
  NotTracked: { tag: "NotTracked" } as AnalyticsError,
};

/**
 * Per-code hit counter. One agent instance per ShortCode.
 *
 * State note: this agent assumes its `count` field initialises to 0 for a
 * freshly-seen code. The test "a fresh Hits key reads count as 0" probes exactly
 * this — if the runtime does not zero-initialise Int state, that probe is where it
 * surfaces (finding #10).
 */
export interface HitsState {
  readonly count: number;
}

const __HitsRegistry = new StateRegistry();
function __zeroOfHitsState(): HitsState { return { count: 0 }; }

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

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

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

  /**
   * Record a hit, returning the new running total.
   */
  async increment(deps: {}): Promise<Result<number, AnalyticsError>> {
    const currentState = await this.loadState();
    const next = currentState.count + 1;
    await this.commitState({ ...currentState, count: next });
    return Ok(next);
  }

  /**
   * Read the current hit count without modifying it.
   */
  async current(deps: {}): Promise<Result<number, AnalyticsError>> {
    const currentState = await this.loadState();
    return Ok(currentState.count);
  }

}

export function __makeHits(key: ShortCode, env?: { HITS?: DurableObjectNamespace }): Hits {
  return makeAgent(__HitsRegistry, env?.HITS, key, (state) => new Hits(state));
}

/**
 * The analytics context's boundary: one service per operation. The service name
 * *is* the operation name, so cross-context callers reach these as
 * `Analytics.track(...)` and `Analytics.count(...)`.
 */
export const track = {
  /**
   * Record a hit against a code and return the new total.
   */
  async call(code: ShortCode, deps: {}): Promise<Result<number, AnalyticsError>> {
    const hits = __makeHits(code);
    const total = await hits.increment(deps);
    return total;
  },
};

export const count = {
  /**
   * Read the current hit count for a code without modifying it.
   */
  async call(code: ShortCode, deps: {}): Promise<Result<number, AnalyticsError>> {
    const hits = __makeHits(code);
    const total = await hits.current(deps);
    return total;
  },
};

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

export interface ShortenerAnalyticsDeps {
}

export function makeSurface(deps: ShortenerAnalyticsDeps) {
  return {
    async track(code: ShortCode): Promise<Result<number, AnalyticsError>> {
      return track.call(code, deps);
    },
    async count(code: ShortCode): Promise<Result<number, AnalyticsError>> {
      return count.call(code, deps);
    },
  };
}

