"/admin/room":
    post:
        tags: [Rooms]
        operationId: adminCreateRoom
        summary: Create an admin-controlled room (broken stub)
        description: |
            **Broken stub** — the handler is empty (`adminCreateRoom` in
            `cloud/src/CloudAdminApi.ts` never calls `res.json` or
            `res.send`), so requests **hang until the client times out**.
            Kept registered for parity with the rest of the room CRUD;
            expect this to land later.
        deprecated: true
        requestBody:
            required: false
            content:
                application/json:
                    schema:
                        type: object
                        additionalProperties: true
        responses:
            "504":
                description: |
                    The handler never responds — gateway timeout (or the
                    client's own timeout) is the most likely outcome. No
                    body shape is documented because no body is sent.
        x-access-policies: [Moderator]

"/admin/room/{roomId}":
    parameters:
        - in: path
          name: roomId
          required: true
          schema: { type: string }
          description: External room id (e.g. `room:abc1234567`).
    get:
        tags: [Rooms]
        operationId: adminGetRoom
        summary: Fetch a room (combined live + stored view)
        description: |
            Returns the combined live + stored view of a room. For lobby / TV rooms
            (which aren't database-backed), the live snapshot's stored projection is
            used. Includes the owner's `AdminAccount` and recent history when the
            room is database-backed.
        responses:
            "200":
                description: Combined room view.
                content:
                    application/json:
                        schema:
                            type: object
                            properties:
                                liveRoom:
                                    $ref: "../components/schemas/LiveRoom.yaml"
                                roomInstances:
                                    type: array
                                    items:
                                        type: object
                                        additionalProperties: true
                                storedRoom:
                                    $ref: "../components/schemas/StoredRoom.yaml"
                                ownerBigscreenAccount:
                                    $ref: "../components/schemas/AdminAccount.yaml"
                                history:
                                    type: array
                                    items:
                                        type: object
                                        additionalProperties: true
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: No room with this id.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]
    put:
        tags: [Rooms]
        operationId: adminUpdateRoom
        summary: Update a room (stored + live)
        description: |
            Moderator update — applies to both the stored row and the live
            Redis snapshot. Most fields on `StoredRoom` are accepted; the
            handler reconciles the live state to match. Returns
            `StoredRoom.getPublicData()` (a subset of the full
            `StoredRoom` schema).
        requestBody:
            required: true
            content:
                application/json:
                    schema:
                        type: object
                        properties:
                            name: { type: string }
                            description: { type: string }
                            visibility: { type: string }
                            category: { type: string }
                            publicTags:
                                type: array
                                items: { type: string }
                            backgroundImageUrl: { type: string, format: uri }
                            images:
                                type: array
                                items: { type: string, format: uri }
                            environmentId: { type: string }
                            maxUsersPerInstance: { type: integer }
                            instancePolicy: { type: string }
                            microphonePolicy: { type: string }
                            movementSoundsPolicy: { type: string }
                            drawingVisibility: { type: string }
                            avatarNameVisibility: { type: string }
                            poseVisibility: { type: string }
                            toySpawnability: { type: string }
                            preferredUserType: { type: string }
                        additionalProperties: true
        responses:
            "200":
                description: Updated room — `StoredRoom.getPublicData()` projection.
                content:
                    application/json:
                        schema: { $ref: "../components/schemas/StoredRoom.yaml" }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: No room with this id.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]
    delete:
        tags: [Rooms]
        operationId: adminDeleteRoom
        summary: Delete a room (or hide it from listings)
        description: |
            Removes the room from the public listings and tears down the
            live snapshot. **Returns plain text `OK`** — not JSON.
        responses:
            "200":
                description: Room deleted. Body is the literal string `OK`.
                content:
                    text/plain:
                        schema: { type: string, example: OK }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: No room with this id.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]

"/admin/room/{roomId}/live":
    parameters:
        - in: path
          name: roomId
          required: true
          schema: { type: string }
    get:
        tags: [Rooms]
        operationId: adminGetLiveRoom
        summary: Live (Redis-backed) room snapshot
        description: |
            Returns just the live Redis snapshot via `getPublicData()` — sanitized
            for non-admin display (no per-session detail). Use the parent
            `GET /admin/room/{roomId}` for the moderator-grade view with sessions.
        responses:
            "200":
                description: Live room (public projection).
                content:
                    application/json:
                        schema: { $ref: "../components/schemas/LiveRoom.yaml" }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: No live room with this id.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]

"/admin/room/{roomId}/history":
    parameters:
        - in: path
          name: roomId
          required: true
          schema: { type: string }
    get:
        tags: [Rooms]
        operationId: getRoomHistory
        summary: Room event history (not implemented)
        description: |
            **Not implemented.** The handler currently throws — the route is
            registered to reserve the path while the underlying audit store is
            being built. Calls return a 500 today.
        responses:
            "500":
                description: Always — handler is a stub.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
        x-access-policies: [Moderator]

"/admin/room/{roomId}/users/{userSessionId}/kick":
    parameters:
        - in: path
          name: roomId
          required: true
          schema: { type: string }
        - in: path
          name: userSessionId
          required: true
          schema: { type: string }
    get:
        tags: [Rooms]
        operationId: adminKickUser
        summary: Kick a user from a room
        description: |
            Forcibly removes the user from whatever room they're in. The
            user is blocked from re-entering until they restart their
            session. Compare to `/eject`, which is recoverable. **Returns
            plain text `OK`** — not JSON.
        responses:
            "200":
                description: Kick acknowledged. Body is the literal string `OK`.
                content:
                    text/plain:
                        schema: { type: string, example: OK }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: No matching session in this room.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]

"/admin/room/{roomId}/users/{userSessionId}/eject":
    parameters:
        - in: path
          name: roomId
          required: true
          schema: { type: string }
        - in: path
          name: userSessionId
          required: true
          schema: { type: string }
    get:
        tags: [Rooms]
        operationId: adminEjectUser
        summary: Eject a user from a room (recoverable)
        description: |
            Removes the user from a room but does not block re-entry. The
            user can rejoin at will. Use for misbehaving users where a kick
            is too heavy-handed. **Returns plain text `OK`** — not JSON.
        responses:
            "200":
                description: Eject acknowledged. Body is the literal string `OK`.
                content:
                    text/plain:
                        schema: { type: string, example: OK }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: No matching session in this room.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]

"/admin/rooms/live":
    get:
        tags: [Rooms]
        operationId: adminGetLiveRooms
        summary: List live rooms (filtered)
        description: |
            Lists currently-live rooms. With no filters, returns every public live
            room. With `roomType=TV` or `roomType=Lobby`, returns the special
            Bigscreen-managed rooms. With `roomType=Cinema`, returns live cinema
            rooms via the stored-room → live-room hydration path.
        parameters:
            - in: query
              name: roomType
              schema:
                  type: string
                  enum: [TV, Lobby, Cinema]
              description: Filter by room type. Other types return 404 by design.
            - in: query
              name: ownerBigscreenAccountId
              schema: { type: string }
        responses:
            "200":
                description: Array of live rooms (public projection).
                content:
                    application/json:
                        schema:
                            type: array
                            items: { $ref: "../components/schemas/LiveRoom.yaml" }
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "404":
                description: Returned for `roomType` outside the supported set.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
            "422":
                description: Invalid query params.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]

"/admin/rooms/environments":
    get:
        tags: [Rooms]
        operationId: adminGetEnvironments
        summary: Environment catalog
        description: |
            Returns the catalog of room environments (scenes the room
            loads on first join). The handler returns
            `CloudDatabase.getEnvironments({})` directly — the response
            shape matches whatever that function returns; treat it as
            opaque on the client.
        responses:
            "200":
                description: Environments catalog (raw output of `getEnvironments`).
                content:
                    application/json:
                        schema:
                            description: Shape per `CloudDatabase.getEnvironments` — opaque to clients.
                            additionalProperties: true
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
        x-access-policies: [Moderator]

"/admin/rooms/all":
    get:
        tags: [Rooms]
        operationId: adminGetRooms
        summary: List stored rooms (filtered)
        description: |
            Lists rows from the persistent stored-room table. Public rooms only —
            does not surface private rooms. Filters by `roomType` and / or
            `ownerBigscreenAccountId`.
        parameters:
            - in: query
              name: roomType
              schema: { type: string }
            - in: query
              name: ownerBigscreenAccountId
              schema: { type: string }
        responses:
            "200":
                description: |
                    Stored rooms — raw output of `CloudDatabase.getStoredRooms`.
                    The wrapper shape (whether `items` / `count` /
                    `totalCount` are present) is determined by that
                    function; treat as opaque on the client.
                content:
                    application/json:
                        schema:
                            description: Shape per `CloudDatabase.getStoredRooms` — opaque to clients.
                            additionalProperties: true
            "401": { $ref: "../cloud-admin-api.yaml#/components/responses/Unauthorized" }
            "403": { $ref: "../cloud-admin-api.yaml#/components/responses/Forbidden" }
            "422":
                description: Invalid query params.
                content:
                    application/json:
                        schema: { $ref: "../cloud-admin-api.yaml#/components/schemas/Error" }
        x-access-policies: [Moderator]
