use actix_web::{HttpRequest, HttpResponse, web};
use channel::ChannelBus;
use channel::http::{WsHandler, WsInMessage};
use serde::Deserialize;
use uuid::Uuid;

use super::rest::{channel_err, extract_user, ok_json};
use crate::error::ApiError;

#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct VoiceMuteRequest {
    pub muted: bool,
}

#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct VoiceDeafRequest {
    pub deafened: bool,
}

#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct ScreenShareRequest {
    pub start: bool,
}

#[utoipa::path(
    post,
    path = "/api/v1/ws/rooms/{room_id}/voice/join",
    responses((status = 204, description = "Joined voice channel")),
    tag = "channel",
)]
pub async fn voice_join(
    req: HttpRequest,
    room_id: web::Path<Uuid>,
    bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
    let user_id = extract_user(&req)?;
    let msg = WsInMessage::VoiceJoin {
        room: room_id.into_inner(),
    };
    let result = WsHandler::handle(&bus, user_id, msg)
        .await
        .map_err(channel_err)?;
    Ok(ok_json(result))
}

#[utoipa::path(
    post,
    path = "/api/v1/ws/rooms/{room_id}/voice/leave",
    responses((status = 204, description = "Left voice channel")),
    tag = "channel",
)]
pub async fn voice_leave(
    req: HttpRequest,
    room_id: web::Path<Uuid>,
    bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
    let user_id = extract_user(&req)?;
    let msg = WsInMessage::VoiceLeave {
        room: room_id.into_inner(),
    };
    let result = WsHandler::handle(&bus, user_id, msg)
        .await
        .map_err(channel_err)?;
    Ok(ok_json(result))
}

#[utoipa::path(
    post,
    path = "/api/v1/ws/rooms/{room_id}/voice/mute",
    request_body = VoiceMuteRequest,
    responses((status = 204, description = "Mute toggled")),
    tag = "channel",
)]
pub async fn voice_mute(
    req: HttpRequest,
    room_id: web::Path<Uuid>,
    body: web::Json<VoiceMuteRequest>,
    bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
    let user_id = extract_user(&req)?;
    let msg = WsInMessage::VoiceMute {
        room: room_id.into_inner(),
        muted: body.muted,
    };
    let result = WsHandler::handle(&bus, user_id, msg)
        .await
        .map_err(channel_err)?;
    Ok(ok_json(result))
}

#[utoipa::path(
    post,
    path = "/api/v1/ws/rooms/{room_id}/voice/deaf",
    request_body = VoiceDeafRequest,
    responses((status = 204, description = "Deaf toggled")),
    tag = "channel",
)]
pub async fn voice_deaf(
    req: HttpRequest,
    room_id: web::Path<Uuid>,
    body: web::Json<VoiceDeafRequest>,
    bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
    let user_id = extract_user(&req)?;
    let msg = WsInMessage::VoiceDeaf {
        room: room_id.into_inner(),
        deafened: body.deafened,
    };
    let result = WsHandler::handle(&bus, user_id, msg)
        .await
        .map_err(channel_err)?;
    Ok(ok_json(result))
}

#[utoipa::path(
    post,
    path = "/api/v1/ws/rooms/{room_id}/screen-share",
    request_body = ScreenShareRequest,
    responses((status = 204, description = "Screen share toggled")),
    tag = "channel",
)]
pub async fn screen_share(
    req: HttpRequest,
    room_id: web::Path<Uuid>,
    body: web::Json<ScreenShareRequest>,
    bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
    let user_id = extract_user(&req)?;
    let msg = WsInMessage::ScreenShare {
        room: room_id.into_inner(),
        start: body.start,
    };
    let result = WsHandler::handle(&bus, user_id, msg)
        .await
        .map_err(channel_err)?;
    Ok(ok_json(result))
}
