use uuid::Uuid;

use crate::{ChannelBus, ChannelResult};

pub(crate) use super::out_event::WsOutEvent;
use super::types::{WS_PROTOCOL_VERSION, WsInMessage};

pub(crate) const MAX_TEXT_LEN: usize = 64 * 1024;
pub(crate) const MAX_MESSAGES_PER_REQUEST: u64 = 100;
pub(crate) const MAX_ROOM_NAME_LEN: usize = 100;
pub(crate) const MAX_CATEGORY_NAME_LEN: usize = 50;

mod helpers;

mod article;
mod ban;
mod category;
mod conversation;
mod draft;
mod forward;
mod invite;
mod message;
mod message_read;
mod notification;
mod pin;
mod presence;
mod reaction;
mod room;
mod search;
mod star;
mod subscription;
mod thread;
mod user;
mod voice;

pub struct WsHandler;

impl WsHandler {
    pub async fn handle(
        bus: &ChannelBus,
        user_id: Uuid,
        msg: WsInMessage,
    ) -> ChannelResult<Option<WsOutEvent>> {
        match msg {
            WsInMessage::Ping => Ok(Some(WsOutEvent::Pong {
                protocol_version: WS_PROTOCOL_VERSION,
            })),
            WsInMessage::Subscribe { room } => {
                Self::subscribe(bus, user_id, room).await
            }
            WsInMessage::Unsubscribe { room } => {
                Self::unsubscribe(bus, user_id, room).await
            }
            WsInMessage::TypingStart { room } => {
                Self::typing(bus, room, user_id, "start").await
            }
            WsInMessage::TypingStop { room } => {
                Self::typing(bus, room, user_id, "stop").await
            }
            WsInMessage::ReadReceipt {
                room,
                last_read_seq,
            } => Self::read_receipt(bus, user_id, room, last_read_seq).await,
            WsInMessage::MessageList {
                room,
                before_seq,
                after_seq,
                limit,
            } => {
                Self::message_list(
                    bus, user_id, room, before_seq, after_seq, limit,
                )
                .await
            }
            WsInMessage::MessageAround {
                room,
                seq,
                limit,
                thread,
            } => {
                Self::message_around(bus, user_id, room, seq, limit, thread)
                    .await
            }
            WsInMessage::MessageCreate {
                room,
                content,
                content_type,
                thread,
                in_reply_to,
            } => {
                Self::message_create(
                    bus,
                    user_id,
                    room,
                    content,
                    content_type,
                    thread,
                    in_reply_to,
                )
                .await
            }
            WsInMessage::MessageUpdate { message, content } => {
                Self::message_update(bus, user_id, message, content).await
            }
            WsInMessage::MessageRevoke { message } => {
                Self::message_revoke(bus, user_id, message).await
            }
            WsInMessage::RoomGet { room } => {
                Self::room_get(bus, user_id, room).await
            }
            WsInMessage::RoomCreate {
                workspace,
                room_name,
                public,
                category,
                ai_enabled,
                channel_type,
            } => {
                Self::room_create(
                    bus, user_id, workspace, room_name, public, category,
                    ai_enabled, channel_type,
                )
                .await
            }
            WsInMessage::RoomUpdate {
                room,
                room_name,
                public,
                category,
                ai_enabled,
            } => {
                Self::room_update(
                    bus, user_id, room, room_name, public, category, ai_enabled,
                )
                .await
            }
            WsInMessage::RoomDelete { room } => {
                Self::room_delete(bus, user_id, room).await
            }
            WsInMessage::CategoryCreate {
                workspace,
                name,
                position,
            } => {
                Self::category_create(bus, user_id, workspace, name, position)
                    .await
            }
            WsInMessage::CategoryUpdate { id, name, position } => {
                Self::category_update(bus, user_id, id, name, position).await
            }
            WsInMessage::CategoryDelete { id } => {
                Self::category_delete(bus, user_id, id).await
            }
            WsInMessage::AccessGrant { room, user } => {
                Self::access_grant(bus, user_id, room, user).await
            }
            WsInMessage::AccessRevoke { room, user } => {
                Self::access_revoke(bus, user_id, room, user).await
            }
            WsInMessage::StateSetReadSeq {
                room,
                last_read_seq,
            } => Self::read_receipt(bus, user_id, room, last_read_seq).await,
            WsInMessage::MissedMessages {
                room,
                after_seq,
                limit,
            } => {
                Self::missed_messages(bus, user_id, room, after_seq, limit)
                    .await
            }
            WsInMessage::CsrfToken => Self::csrf_token(bus, user_id).await,
            WsInMessage::StateUpdateDnd {
                room,
                do_not_disturb,
                dnd_start_hour,
                dnd_end_hour,
            } => {
                Self::dnd_update(
                    bus,
                    user_id,
                    room,
                    do_not_disturb,
                    dnd_start_hour,
                    dnd_end_hour,
                )
                .await
            }
            WsInMessage::ReactionAdd {
                room,
                message,
                emoji,
            } => Self::reaction_add(bus, user_id, room, message, emoji).await,
            WsInMessage::ReactionRemove {
                room,
                message,
                emoji,
            } => {
                Self::reaction_remove(bus, user_id, room, message, emoji).await
            }
            WsInMessage::ThreadCreate { room, parent } => {
                Self::thread_create(bus, user_id, room, parent).await
            }
            WsInMessage::ThreadList { room } => {
                Self::thread_list(bus, user_id, room).await
            }
            WsInMessage::ThreadResolve { thread_id } => {
                Self::thread_resolve(bus, user_id, thread_id).await
            }
            WsInMessage::ThreadArchive { thread_id } => {
                Self::thread_archive(bus, user_id, thread_id).await
            }
            WsInMessage::PinAdd { room, message } => {
                Self::pin_add(bus, user_id, room, message).await
            }
            WsInMessage::PinRemove { room, message } => {
                Self::pin_remove(bus, user_id, room, message).await
            }
            WsInMessage::DraftSave { room, content } => {
                Self::draft_save(bus, user_id, room, content).await
            }
            WsInMessage::DraftClear { room } => {
                Self::draft_clear(bus, user_id, room).await
            }
            WsInMessage::NotificationMarkRead { id } => {
                Self::notification_mark_read(bus, user_id, id).await
            }
            WsInMessage::NotificationMarkAllRead { workspace_id } => {
                Self::notification_mark_all_read(bus, user_id, workspace_id)
                    .await
            }
            WsInMessage::NotificationArchive { id } => {
                Self::notification_archive(bus, user_id, id).await
            }
            WsInMessage::PresenceUpdate { status } => {
                Self::presence_update(bus, user_id, status).await
            }
            WsInMessage::CustomStatusUpdate {
                emoji,
                text,
                expires_at,
            } => {
                Self::custom_status_update(
                    bus, user_id, emoji, text, expires_at,
                )
                .await
            }
            WsInMessage::InviteCreate {
                workspace,
                room,
                max_uses,
                expires_at,
            } => {
                Self::invite_create(
                    bus, user_id, workspace, room, max_uses, expires_at,
                )
                .await
            }
            WsInMessage::InviteAccept { code } => {
                Self::invite_accept(bus, user_id, code).await
            }
            WsInMessage::InviteRevoke { id } => {
                Self::invite_revoke(bus, user_id, id).await
            }
            WsInMessage::BanCreate {
                workspace,
                user,
                reason,
                expires_at,
            } => {
                Self::ban_create(
                    bus, user_id, workspace, user, reason, expires_at,
                )
                .await
            }
            WsInMessage::BanRemove { workspace, user } => {
                Self::ban_remove(bus, user_id, workspace, user).await
            }
            WsInMessage::VoiceJoin { room } => {
                Self::voice_join(bus, user_id, room).await
            }
            WsInMessage::VoiceLeave { room } => {
                Self::voice_leave(bus, user_id, room).await
            }
            WsInMessage::VoiceMute { room, muted } => {
                Self::voice_mute(bus, user_id, room, muted).await
            }
            WsInMessage::VoiceDeaf { room, deafened } => {
                Self::voice_deaf(bus, user_id, room, deafened).await
            }
            WsInMessage::ScreenShare { room, start } => {
                Self::screen_share(bus, user_id, room, start).await
            }
            WsInMessage::UserSummary { username } => {
                Self::user_summary(bus, username).await
            }
            WsInMessage::Search {
                q,
                room,
                limit,
                offset,
                ..
            } => Self::search(bus, user_id, q, room, limit, offset).await,
            WsInMessage::ConversationPin { room, pin } => {
                Self::conversation_pin(bus, user_id, room, pin).await
            }
            WsInMessage::ConversationMute { room, mute } => {
                Self::conversation_mute(bus, user_id, room, mute).await
            }
            WsInMessage::ConversationNotifyLevel { room, notify_level } => {
                Self::conversation_notify_level(
                    bus,
                    user_id,
                    room,
                    notify_level,
                )
                .await
            }
            WsInMessage::ConversationList => {
                Self::conversation_list(bus, user_id).await
            }

            WsInMessage::MessageMarkRead { room, message_ids } => {
                Self::message_mark_read(bus, user_id, room, message_ids).await
            }
            WsInMessage::MessageGetReaders { message_id } => {
                Self::message_get_readers(bus, user_id, message_id).await
            }
            WsInMessage::MessageStar {
                room,
                message,
                star,
            } => Self::message_star(bus, user_id, room, message, star).await,
            WsInMessage::StarredList { room, limit } => {
                Self::starred_list(bus, user_id, room, limit).await
            }
            WsInMessage::MessageForward {
                source_message_id,
                target_room,
            } => {
                Self::message_forward(
                    bus,
                    user_id,
                    source_message_id,
                    target_room,
                )
                .await
            }
            WsInMessage::ArticleCreate {
                channel,
                title,
                cover_url,
                content,
                content_type,
                summary,
                tags,
                status,
            } => {
                Self::article_create(
                    bus, user_id, channel, title, cover_url, content,
                    content_type, summary, tags, status,
                )
                .await
            }
            WsInMessage::ArticleUpdate {
                article_id,
                title,
                cover_url,
                content,
                content_type,
                summary,
                tags,
                is_pinned,
                status,
            } => {
                Self::article_update(
                    bus, user_id, article_id, title, cover_url, content,
                    content_type, summary, tags, is_pinned, status,
                )
                .await
            }
            WsInMessage::ArticleDelete { article_id } => {
                Self::article_delete(bus, user_id, article_id).await
            }
            WsInMessage::ArticleList {
                channel,
                before,
                limit,
            } => {
                Self::article_list(bus, user_id, channel, before, limit).await
            }
            WsInMessage::ArticleGet { article_id } => {
                Self::article_get(bus, user_id, article_id).await
            }
            WsInMessage::ArticleLike { article_id, like } => {
                Self::article_like(bus, user_id, article_id, like).await
            }
            WsInMessage::ArticleCommentCreate {
                article_id,
                content,
                parent,
            } => {
                Self::article_comment_create(
                    bus, user_id, article_id, content, parent,
                )
                .await
            }
            WsInMessage::ArticleCommentDelete { comment_id } => {
                Self::article_comment_delete(bus, user_id, comment_id).await
            }
            WsInMessage::ArticleCommentList {
                article_id,
                before,
                limit,
            } => {
                Self::article_comment_list(
                    bus, user_id, article_id, before, limit,
                )
                .await
            }
            WsInMessage::ArticleLikedUsers {
                article_id,
                before,
                limit,
            } => {
                Self::article_liked_users(
                    bus, user_id, article_id, before, limit,
                )
                .await
            }
        }
    }
}
