import { Hono } from "hono";
import { userFromAuthHeader } from "../auth.js";
import type { LobbyRecord, Store } from "../db/store.js";

/** Lobby lifecycle — GDD §9. Signalling itself lives in `src/ws/`. */

export function lobbyRoutes(store: Store) {
  const app = new Hono();

  app.post("/", async (context) => {
    const user = await userFromAuthHeader(store, context.req.header("authorization"));
    if (!user) return context.json({ error: "unauthorized" }, 401);

    const body = (await context.req.json().catch(() => null)) as {
      settings?: Record<string, unknown>;
    } | null;

    const lobby = await store.createLobby(
      user.id,
      user.displayName ?? user.username,
      body?.settings ?? {},
    );
    return context.json(publicLobby(lobby), 201);
  });

  app.get("/:code", async (context) => {
    const lobby = await store.findLobbyByCode(context.req.param("code"));
    if (!lobby) return context.json({ error: "lobby not found" }, 404);
    return context.json(publicLobby(lobby));
  });

  app.post("/:code/join", async (context) => {
    const user = await userFromAuthHeader(store, context.req.header("authorization"));
    if (!user) return context.json({ error: "unauthorized" }, 401);

    const result = await store.joinLobby(
      context.req.param("code"),
      user.id,
      user.displayName ?? user.username,
    );

    if ("error" in result) {
      const status = result.error === "lobby not found" ? 404 : 409;
      return context.json({ error: result.error }, status);
    }
    return context.json(publicLobby(result));
  });

  app.post("/:code/ready", async (context) => {
    const user = await userFromAuthHeader(store, context.req.header("authorization"));
    if (!user) return context.json({ error: "unauthorized" }, 401);

    const body = (await context.req.json().catch(() => null)) as { isReady?: unknown } | null;
    const lobby = await store.setReady(
      context.req.param("code"),
      user.id,
      body?.isReady === true,
    );
    if (!lobby) return context.json({ error: "lobby not found" }, 404);
    return context.json(publicLobby(lobby));
  });

  app.post("/:code/leave", async (context) => {
    const user = await userFromAuthHeader(store, context.req.header("authorization"));
    if (!user) return context.json({ error: "unauthorized" }, 401);

    const lobby = await store.leaveLobby(context.req.param("code"), user.id);
    if (!lobby) return context.json({ error: "lobby not found" }, 404);
    return context.json(publicLobby(lobby));
  });

  app.post("/:code/start", async (context) => {
    const user = await userFromAuthHeader(store, context.req.header("authorization"));
    if (!user) return context.json({ error: "unauthorized" }, 401);

    const lobby = await store.findLobbyByCode(context.req.param("code"));
    if (!lobby) return context.json({ error: "lobby not found" }, 404);
    if (lobby.hostId !== user.id) return context.json({ error: "only the host can start" }, 403);

    const notReady = lobby.players.filter((player) => !player.isReady);
    if (notReady.length > 0) {
      return context.json(
        { error: "not everyone is ready", waitingOn: notReady.map((p) => p.displayName) },
        409,
      );
    }

    const started = await store.setLobbyStatus(lobby.code, "in_game");
    return context.json(publicLobby(started!));
  });

  return app;
}

/** Strips internal user ids; peers address each other by peer id only. */
function publicLobby(lobby: LobbyRecord) {
  return {
    code: lobby.code,
    status: lobby.status,
    maxPlayers: lobby.maxPlayers,
    settings: lobby.settings,
    createdAt: lobby.createdAt,
    expiresAt: lobby.expiresAt,
    players: lobby.players.map((player) => ({
      peerId: player.peerId,
      displayName: player.displayName,
      isReady: player.isReady,
      isHost: player.userId === lobby.hostId,
    })),
  };
}
