use uuid::Uuid;

use crate::event::{RoomInfo, forward};
use crate::{ChannelBus, ChannelResult};

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

impl WsHandler {
    pub(super) async fn message_forward(
        bus: &ChannelBus,
        user_id: Uuid,
        source_message_id: Uuid,
        target_room: Uuid,
    ) -> ChannelResult<Option<WsOutEvent>> {
        let source = Self::load_message(bus, source_message_id).await?;

        Self::ensure_room_access(bus, user_id, source.room).await?;
        Self::ensure_room_access(bus, user_id, target_room).await?;

        let seq = bus.inner.seq.seq(target_room).await?;
        let sender = bus.lookup_user(user_id).await?;

        let source_room_info = bus
            .lookup_room(source.room)
            .await
            .unwrap_or_else(|_| RoomInfo::unknown(source.room));
        let forward_content = format!(
            "> Forwarded from {}:\n\n{}",
            source_room_info.name, source.content
        );

        let metadata = serde_json::json!({
            "source_room_id": source.room,
            "source_message_id": source.id,
            "source_room_name": source_room_info.name,
            "forwarded_by": user_id,
        });

        let row = db::sqlx::query_as::<_, model::channel::RoomMessageModel>(
            "INSERT INTO room_message \
             (room, seq, thread, parent, author, content, content_type, system_type, metadata) \
             VALUES ($1, $2, NULL, NULL, $3, $4, 'forward', NULL, $5) \
             RETURNING id, room, seq, thread, parent, author, content, content_type, pinned, \
             system_type, metadata, edited_at, created_at, updated_at, deleted_at",
        )
        .bind(target_room)
        .bind(seq)
        .bind(user_id)
        .bind(&forward_content)
        .bind(&metadata)
        .fetch_one(bus.inner.db.writer())
        .await?;

        let target_room_info = bus
            .lookup_room(target_room)
            .await
            .unwrap_or_else(|_| RoomInfo::unknown(target_room));

        let fwd_id = row.id;
        let fwd_seq = row.seq;
        let fwd_content = row.content.clone();
        let fwd_content_type = row.content_type.clone();
        let fwd_created_at = row.created_at;

        bus.publish_room_message(row, Some(bus.lookup_user(user_id).await?))
            .await?;

        let data = forward::MessageForwardedService {
            id: fwd_id,
            seq: fwd_seq,
            room: target_room_info.clone(),
            sender,
            content: fwd_content,
            content_type: fwd_content_type,
            source_room: source_room_info,
            source_message_id: source.id,
            forwarded_at: fwd_created_at,
        };

        Ok(Some(WsOutEvent::MessageForwarded {
            room: target_room_info,
            data,
        }))
    }
}
