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

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

export type RoomId = string & { readonly __brand: "chat.RoomId" };

export const RoomId = {
  of(value: string): Result<RoomId, ValidationError> {
    return Ok(value as RoomId);
  },
  unsafe(value: string): RoomId {
    return value as RoomId;
  },
};

export type UserId = string & { readonly __brand: "chat.UserId" };

export const UserId = {
  of(value: string): Result<UserId, ValidationError> {
    return Ok(value as UserId);
  },
  unsafe(value: string): UserId {
    return value as UserId;
  },
};

export interface ServerFrame {
  readonly text: string;
}

export const ServerFrame = {
};

export interface ClientFrame {
  readonly text: string;
}

export const ClientFrame = {
};

export const ChatGateway = {
  async open(connection: Connection<ServerFrame>, roomId: RoomId, deps: { identity: UserId }): Promise<void> {
    const __r0 = await (connection).send({ text: "welcome" });
    const __r1 = await __makeRoom(roomId).join(deps.identity, connection, deps);
    return undefined;
  },
  async message(connection: Connection<ServerFrame>, roomId: RoomId, frame: ClientFrame, deps: { identity: UserId }): Promise<void> {
    const __r0 = await __makeRoom(roomId).post(deps.identity, frame.text, deps);
    return undefined;
  },
  async close(connection: Connection<ServerFrame>, roomId: RoomId, deps: { identity: UserId }): Promise<void> {
    const __r0 = await __makeRoom(roomId).leave(deps.identity, deps);
    return undefined;
  },
};

export interface RoomState {
  readonly conns: Record<string, Connection<ServerFrame>>;
  readonly members: Record<string, boolean>;
}

const __RoomRegistry = new StateRegistry();
function __zeroOfRoomState(): RoomState { return { conns: {}, members: {} }; }

function __rehydrateRoomState(s: RoomState): void {
  for (const __k of Object.keys(s.conns)) { const __r = deserialise_UserId((__k as unknown as JsonValue), "conns"); if (__r.tag === "Err") throw rehydrationViolation("Room", __r.error); }
  for (const __k of Object.keys(s.members)) { const __r = deserialise_UserId((__k as unknown as JsonValue), "members"); if (__r.tag === "Err") throw rehydrationViolation("Room", __r.error); }
}

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

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

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

  async join(u: UserId, conn: Connection<ServerFrame>, deps: {}): Promise<void> {
    const __state = { ...(await this.loadState()) };
    const __result = await (async () => {
      const __r0 = await ((__state.members[u] = true), undefined);
      const __r1 = await ((__state.conns[u] = conn), undefined);
      return undefined;
    })();
    await this.commitState(__state);
    return __result;
  }

  async leave(u: UserId, deps: {}): Promise<void> {
    const __state = { ...(await this.loadState()) };
    const __result = await (async () => {
      const __r0 = await ((delete __state.members[u]), undefined);
      const __r1 = await ((delete __state.conns[u]), undefined);
      return undefined;
    })();
    await this.commitState(__state);
    return __result;
  }

  async post(sender: UserId, text: string, deps: {}): Promise<void> {
    const __state = await this.loadState();
    const __r0 = await (async () => { await Promise.all(Object.values(__state.conns).map((__x) => (async (c: Connection<ServerFrame>) => (c).send({ text: text }))(__x))); })();
    return undefined;
  }

}

export function __makeRoom(key: RoomId, env?: { ROOM?: DurableObjectNamespace }): Room {
  return makeAgent(__RoomRegistry, env?.ROOM, key, (state) => new Room(state));
}

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

export interface ChatDeps {
}

export function makeSurface(deps: ChatDeps) {
  return {
  };
}

export function serialise_UserId(value: UserId): JsonValue {
  return value as unknown as string;
}

export function deserialise_UserId(json: JsonValue, path: string = "$"): Result<UserId, BoundaryError> {
  if (typeof json !== "string") {
    return Err({ kind: "StructuralMismatch", path, expected: "string", actual: typeof json });
  }
  const validated = (typeof (UserId as any).of === "function")
    ? (UserId as any).of(json)
    : Ok(json as unknown as UserId);
  if (validated.tag === "Err") {
    return Err({ kind: "RefinementViolation", path, violation: validated.error });
  }
  return Ok(validated.value as UserId);
}


