// 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, resolveConnection, connIdOf, acceptHibernatableConnection, newWebSocketPair, webSocketUpgradeResponse, type JsonValue, type BoundaryError, type ServiceBinding, callService, 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 = {
};

export interface RoomState {
  readonly conns: Record<string, string>;
  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[String(u)] = connIdOf(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 (async () => { const __k = String(u); const __cid = __state.conns[__k]; if (__cid !== undefined) { const __c = resolveConnection<ServerFrame>(this.state, __cid); if (__c.tag === "Some") { await __c.value.close(); } delete __state.conns[__k]; } return undefined; })();
      return undefined;
    })();
    await this.commitState(__state);
    return __result;
  }

  async __wsOpen_ChatGateway(connection: Connection<ServerFrame>, roomId: RoomId, deps: { identity: UserId }): Promise<void> {
    const __r0 = await (connection).send({ text: "welcome" });
    const __r1 = await this.join(deps.identity, connection, deps);
    return undefined;
  }

  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    if (url.pathname === "/_bynk/ws/open/ChatGateway") {
      const __pair = newWebSocketPair();
      const __payload = JSON.parse(request.headers.get("X-Bynk-Ws-Open") ?? "{}") as { args: unknown[]; identity: string };
      const connection = acceptHibernatableConnection<ServerFrame>(this.state, __pair.server);
      await this.__wsOpen_ChatGateway(connection, __payload.args[0] as RoomId, { identity: __payload.identity as UserId });
      return webSocketUpgradeResponse(__pair.client);
    }
    if (url.pathname.startsWith("/_bynk/agent/")) {
      const methodName = url.pathname.slice("/_bynk/agent/".length);
      const { args, deps } = (await request.json()) as { args: unknown[]; deps: unknown };
      const result = await (this as any)[methodName](...args, deps);
      return new Response(JSON.stringify(result), { headers: { "content-type": "application/json" } });
    }
    return new Response("Not Found", { status: 404 });
  }

}

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 function serialise_RoomId(value: RoomId): JsonValue {
  return value as unknown as string;
}

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

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);
}


