use crate::{ApiResponse, error::ApiError};
use actix_web::{HttpResponse, Result, web};
use room::ws_context::WsUserContext;
use service::AppService;
use session::Session;
use utoipa::IntoParams;
use uuid::Uuid;

#[derive(Debug, serde::Deserialize, IntoParams)]
pub struct NotificationListQuery {
    pub only_unread: Option<bool>,
    pub archived: Option<bool>,
    pub limit: Option<u64>,
}

#[utoipa::path(
    get,
    path = "/api/me/notifications",
    params(
        ("only_unread" = Option<bool>, Query),
        ("archived" = Option<bool>, Query),
        ("limit" = Option<u64>, Query),
    ),
    responses(
        (status = 200, description = "List notifications", body = ApiResponse<room::NotificationListResponse>),
        (status = 401, description = "Unauthorized"),
    ),
    tag = "Room"
)]
pub async fn notification_list(
    service: web::Data<AppService>,
    session: Session,
    query: web::Query<NotificationListQuery>,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or_else(|| ApiError::from(service::error::AppError::Unauthorized))?;
    let ctx = WsUserContext::new(user_id);
    let resp = service
        .room
        .notification_list(query.only_unread, query.archived, query.limit, &ctx)
        .await
        .map_err(ApiError::from)?;
    Ok(ApiResponse::ok(resp).to_response())
}

#[utoipa::path(
    post,
    path = "/api/me/notifications/{notification_id}/read",
    params(
        ("notification_id" = Uuid, Path),
    ),
    responses(
        (status = 200, description = "Mark notification as read"),
        (status = 401, description = "Unauthorized"),
        (status = 404, description = "Not found"),
    ),
    tag = "Room"
)]
pub async fn notification_mark_read(
    service: web::Data<AppService>,
    session: Session,
    path: web::Path<Uuid>,
) -> Result<HttpResponse, ApiError> {
    let notification_id = path.into_inner();
    let user_id = session
        .user()
        .ok_or_else(|| ApiError::from(service::error::AppError::Unauthorized))?;
    let ctx = WsUserContext::new(user_id);
    service
        .room
        .notification_mark_read(notification_id, &ctx)
        .await
        .map_err(ApiError::from)?;
    Ok(ApiResponse::ok(true).to_response())
}

#[utoipa::path(
    post,
    path = "/api/me/notifications/read-all",
    responses(
        (status = 200, description = "Mark all notifications as read"),
        (status = 401, description = "Unauthorized"),
    ),
    tag = "Room"
)]
pub async fn notification_mark_all_read(
    service: web::Data<AppService>,
    session: Session,
) -> Result<HttpResponse, ApiError> {
    let user_id = session
        .user()
        .ok_or_else(|| ApiError::from(service::error::AppError::Unauthorized))?;
    let ctx = WsUserContext::new(user_id);
    let count = service
        .room
        .notification_mark_all_read(&ctx)
        .await
        .map_err(ApiError::from)?;
    Ok(ApiResponse::ok(count).to_response())
}

#[utoipa::path(
    post,
    path = "/api/me/notifications/{notification_id}/archive",
    params(
        ("notification_id" = Uuid, Path),
    ),
    responses(
        (status = 200, description = "Archive notification"),
        (status = 401, description = "Unauthorized"),
        (status = 404, description = "Not found"),
    ),
    tag = "Room"
)]
pub async fn notification_archive(
    service: web::Data<AppService>,
    session: Session,
    path: web::Path<Uuid>,
) -> Result<HttpResponse, ApiError> {
    let notification_id = path.into_inner();
    let user_id = session
        .user()
        .ok_or_else(|| ApiError::from(service::error::AppError::Unauthorized))?;
    let ctx = WsUserContext::new(user_id);
    service
        .room
        .notification_archive(notification_id, &ctx)
        .await
        .map_err(ApiError::from)?;
    Ok(ApiResponse::ok(true).to_response())
}
