use chrono::Utc;
use uuid::Uuid;

use crate::event::{RoomInfo, UserInfo, voice};
use crate::{ChannelBus, ChannelResult};

use super::WsHandler;
use super::WsOutEvent;

impl WsHandler {
    pub(super) async fn voice_join(
        bus: &ChannelBus,
        user_id: Uuid,
        room: Uuid,
    ) -> ChannelResult<Option<WsOutEvent>> {
        Self::ensure_room_access(bus, user_id, room).await?;
        let vj_room = bus
            .lookup_room(room)
            .await
            .unwrap_or_else(|_| RoomInfo::unknown(room));
        let vj_user = bus
            .lookup_user(user_id)
            .await
            .unwrap_or_else(|_| UserInfo::unknown(user_id));
        let data = voice::VoiceChannelJoinedService {
            room: vj_room,
            workspace: None,
            user: vj_user,
            muted: false,
            deafened: false,
            video: false,
            joined_at: Utc::now(),
        };
        bus.publish_room_event(room, "voice.channel_joined", &data)
            .await?;
        Ok(Some(WsOutEvent::VoiceChannelJoined {
            room: data.room.clone(),
            data,
        }))
    }

    pub(super) async fn voice_leave(
        bus: &ChannelBus,
        user_id: Uuid,
        room: Uuid,
    ) -> ChannelResult<Option<WsOutEvent>> {
        Self::ensure_room_access(bus, user_id, room).await?;
        let vl_room = bus
            .lookup_room(room)
            .await
            .unwrap_or_else(|_| RoomInfo::unknown(room));
        let vl_user = bus
            .lookup_user(user_id)
            .await
            .unwrap_or_else(|_| UserInfo::unknown(user_id));
        let data = voice::VoiceChannelLeftService {
            room: vl_room,
            workspace: None,
            user: vl_user,
            left_at: Utc::now(),
        };
        bus.publish_room_event(room, "voice.channel_left", &data)
            .await?;
        Ok(Some(WsOutEvent::VoiceChannelLeft {
            room: data.room.clone(),
            data,
        }))
    }

    pub(super) async fn voice_mute(
        bus: &ChannelBus,
        user_id: Uuid,
        room: Uuid,
        muted: bool,
    ) -> ChannelResult<Option<WsOutEvent>> {
        Self::ensure_room_access(bus, user_id, room).await?;
        bus.publish_room_event(
            room,
            "voice.mute_updated",
            &serde_json::json!({"user_id": user_id, "muted": muted}),
        )
        .await?;
        Ok(None)
    }

    pub(super) async fn voice_deaf(
        bus: &ChannelBus,
        user_id: Uuid,
        room: Uuid,
        deafened: bool,
    ) -> ChannelResult<Option<WsOutEvent>> {
        Self::ensure_room_access(bus, user_id, room).await?;
        bus.publish_room_event(
            room,
            "voice.deaf_updated",
            &serde_json::json!({"user_id": user_id, "deafened": deafened}),
        )
        .await?;
        Ok(None)
    }

    pub(super) async fn screen_share(
        bus: &ChannelBus,
        user_id: Uuid,
        room: Uuid,
        start: bool,
    ) -> ChannelResult<Option<WsOutEvent>> {
        Self::ensure_room_access(bus, user_id, room).await?;
        bus.publish_room_event(
            room,
            "voice.screen_share",
            &serde_json::json!({"user_id": user_id, "start": start}),
        )
        .await?;
        Ok(None)
    }
}
