use crate::controllers::HttpResult;
use crate::extractors::auth_extractor::AuthExtractor;
use crate::extractors::inbox_entry_extractor::InboxEntryInPath;
use crate::services::inbox_service;
use crate::services::inbox_service::UpdateInboxEntryQuery;
use actix_web::{HttpResponse, web};

/// Create a new inbox entry
pub async fn create(auth: AuthExtractor, req: web::Json<UpdateInboxEntryQuery>) -> HttpResult {
    if let Some(err) = req.check_error(auth.user_id()).await? {
        return Ok(HttpResponse::BadRequest().json(err));
    }

    inbox_service::create(auth.user_id(), &req).await?;

    Ok(HttpResponse::Created().finish())
}

#[derive(serde::Deserialize)]
pub struct GetInboxQuery {
    #[serde(default)]
    include_attached: bool,
}

/// Get inbox content
pub async fn get_list(auth: AuthExtractor, query: web::Query<GetInboxQuery>) -> HttpResult {
    let mut list = inbox_service::get_list_user(auth.user_id()).await?;

    list.retain(|entry| {
        if !query.include_attached && entry.movement_id().is_some() {
            return false;
        }

        true
    });

    Ok(HttpResponse::Ok().json(list))
}

#[derive(serde::Serialize)]
struct InboxCount {
    count: usize,
}

/// Count the number of inbox entries
pub async fn count_entries(auth: AuthExtractor, query: web::Query<GetInboxQuery>) -> HttpResult {
    let mut list = inbox_service::get_list_user(auth.user_id()).await?;

    list.retain(|entry| {
        if !query.include_attached && entry.movement_id().is_some() {
            return false;
        }

        true
    });

    Ok(HttpResponse::Ok().json(InboxCount { count: list.len() }))
}

/// Get a single inbox entry
pub async fn get_single(entry: InboxEntryInPath) -> HttpResult {
    Ok(HttpResponse::Ok().json(entry.as_ref()))
}

/// Update a single inbox entry information
pub async fn update(
    auth: AuthExtractor,
    inbox_entry: InboxEntryInPath,
    req: web::Json<UpdateInboxEntryQuery>,
) -> HttpResult {
    if let Some(err) = req.check_error(auth.user_id()).await? {
        return Ok(HttpResponse::BadRequest().json(err));
    }

    inbox_service::update(inbox_entry.as_ref().id(), &req).await?;

    Ok(HttpResponse::Ok().json(inbox_service::get_by_id(inbox_entry.as_ref().id()).await?))
}

/// Delete a single inbox entry
pub async fn delete(inbox_entry: InboxEntryInPath) -> HttpResult {
    inbox_service::delete(inbox_entry.as_ref().id()).await?;
    Ok(HttpResponse::Accepted().finish())
}
