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

use crate::event::{UserInfo, notify};
use crate::{ChannelBus, ChannelError, ChannelResult};

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

impl WsHandler {
    pub(super) async fn notification_mark_read(
        bus: &ChannelBus,
        user_id: Uuid,
        id: Uuid,
    ) -> ChannelResult<Option<WsOutEvent>> {
        let result = db::sqlx::query(
            "UPDATE user_app_notify SET read_at = now(), updated_at = now() \
             WHERE id = $1 AND \"user\" = $2 AND read_at IS NULL AND archived_at IS NULL",
        )
        .bind(id)
        .bind(user_id)
        .execute(bus.inner.db.writer())
        .await?;
        if result.rows_affected() == 0 {
            return Err(ChannelError::RoomNotFound);
        }
        let nr_user = bus
            .lookup_user(user_id)
            .await
            .unwrap_or_else(|_| UserInfo::unknown(user_id));
        let data = notify::NotifyReadService {
            id,
            user: nr_user,
            read_at: Utc::now(),
        };
        Ok(Some(WsOutEvent::NotifyRead { data }))
    }

    pub(super) async fn notification_mark_all_read(
        bus: &ChannelBus,
        user_id: Uuid,
        workspace_id: Option<Uuid>,
    ) -> ChannelResult<Option<WsOutEvent>> {
        if let Some(wk) = workspace_id {
            db::sqlx::query(
                "UPDATE user_app_notify SET read_at = now(), updated_at = now() \
                 WHERE \"user\" = $1 AND target_id = $2 AND read_at IS NULL",
            )
            .bind(user_id)
            .bind(wk)
            .execute(bus.inner.db.writer())
            .await?;
        } else {
            db::sqlx::query(
                "UPDATE user_app_notify SET read_at = now(), updated_at = now() \
                 WHERE \"user\" = $1 AND read_at IS NULL",
            )
            .bind(user_id)
            .execute(bus.inner.db.writer())
            .await?;
        }
        Ok(None)
    }

    pub(super) async fn notification_archive(
        bus: &ChannelBus,
        user_id: Uuid,
        id: Uuid,
    ) -> ChannelResult<Option<WsOutEvent>> {
        db::sqlx::query(
            "UPDATE user_app_notify SET archived_at = now(), updated_at = now() \
             WHERE id = $1 AND \"user\" = $2 AND archived_at IS NULL",
        )
        .bind(id)
        .bind(user_id)
        .execute(bus.inner.db.writer())
        .await?;
        Ok(None)
    }
}
