//! Room lifecycle operations delegated to [`crate::repo::traits::ChatRepository`].

use std::sync::Arc;

use sqlx::PgPool;

use crate::dto::commands::{ArchiveRoom, CreateRoom, ListRooms, UpdateRoom};
use crate::dto::results::{RoomPage, RoomView};
use crate::error::ChatResult;
use crate::ids::RoomId;
use crate::repo::traits::{ChatRepository, RoomCommit};

/// Room facade used by [`crate::SqlxChatApp`].
#[derive(Clone)]
pub struct RoomService {
    repo: Arc<dyn ChatRepository>,
}

impl RoomService {
    /// Constructs a service backed by the given repository.
    pub fn new(repo: Arc<dyn ChatRepository>) -> Self {
        Self { repo }
    }

    /// Creates a room with initial members and returns an outbox commit.
    pub async fn create_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: CreateRoom,
    ) -> ChatResult<RoomCommit> {
        self.repo
            .create_room(pool, organization_id, actor, input)
            .await
    }

    /// Updates room metadata and returns an outbox commit.
    pub async fn update_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: UpdateRoom,
    ) -> ChatResult<RoomCommit> {
        self.repo
            .update_room(pool, organization_id, actor, input)
            .await
    }

    /// Archives a room and returns an outbox commit.
    pub async fn archive_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: ArchiveRoom,
    ) -> ChatResult<RoomCommit> {
        self.repo
            .archive_room(pool, organization_id, actor, input.room_id)
            .await
    }

    /// Lists rooms visible to `actor` within the organization.
    pub async fn list_rooms(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        input: ListRooms,
    ) -> ChatResult<RoomPage> {
        self.repo
            .list_rooms(pool, organization_id, actor, input)
            .await
    }

    /// Fetches a single room when `actor` is a visible member.
    pub async fn get_room(
        &self,
        pool: &PgPool,
        organization_id: &str,
        actor: &str,
        room_id: RoomId,
    ) -> ChatResult<RoomView> {
        self.repo
            .get_room(pool, organization_id, actor, room_id)
            .await
    }
}
