use actix_web::{get, post, web, HttpResponse, HttpRequest, ResponseError};
use log::error;
use serde::{Serialize, Deserialize};
use siren::{Response, Metadata, ServiceError};

use crate::{storage::messages::{QueryMessage, QueryFilters, InsertMessage}, auth::{JwtAuth, verify_role}};

#[derive(Serialize, Deserialize)]
struct GetAllParams {
  id: Option<String>,
  guild_id: Option<i64>,
  channel_id: Option<i64>,
  user_id: Option<i64>,
  model: Option<String>,
  request: Option<String>,
  response: Option<String>,
  request_tags: Option<Vec<String>>,
  response_tags: Option<Vec<String>>,
  limit: Option<i32>,
  page: Option<i32>,
}

#[get("/messages")]
async fn get_all(req: HttpRequest, auth: JwtAuth) -> HttpResponse {
  let _ = match verify_role(&auth, "admin") {
    Ok(_) => {},
    Err(err) => return ResponseError::error_response(&err)
  };
  let params = match web::Query::<GetAllParams>::from_query(req.query_string()) {
    Ok(params) => params,
    Err(err) => return ResponseError::error_response(&ServiceError {
      status: 422,
      message: err.to_string()
    })
  };
  let mut filters = QueryFilters::default();
  filters.by_id = params.id.clone();
  filters.by_guild_id = params.guild_id;
  filters.by_channel_id = params.channel_id;
  filters.by_user_id = params.user_id;
  filters.by_model = params.model.clone();
  filters.by_request = params.request.clone();
  filters.by_response = params.response.clone();
  filters.by_request_tags = params.request_tags.clone();
  filters.by_response_tags = params.response_tags.clone();
  let limit = params.limit.unwrap_or(100);
  let total_count = QueryMessage::get_count(&filters).unwrap();
  let max_page = std::cmp::max((total_count as f64 / limit as f64).ceil() as i32, 1);
  let page = std::cmp::min(std::cmp::max(params.page.unwrap_or(1), 1), max_page);
  
  match QueryMessage::get_all(&filters, limit, page) {
    Ok(messages) => {
      HttpResponse::Ok().json(Response {
        data: messages,
        metadata: Some(Metadata {
          total: total_count as i32,
          limit,
          page,
          pages: max_page
        })
      })
    },
    Err(err) => {
      error!("{:?}", err.message);
      ResponseError::error_response(&err)
    }
  }
}

#[post("/messages")]
async fn create(message: web::Json<InsertMessage>, auth: JwtAuth) -> HttpResponse {
  let _ = match verify_role(&auth, "admin") {
    Ok(_) => {},
    Err(err) => return ResponseError::error_response(&err)
  };
  match InsertMessage::insert(message.into_inner()) {
    Ok(message) => HttpResponse::Created().json(message),
    Err(err) => {
      error!("{:?}", err.message);
      ResponseError::error_response(&err)
    }
  }
}

pub fn init_routes(config: &mut web::ServiceConfig) {
  config.service(get_all);
  config.service(create);
}