use actix_identity::Identity;
use actix_web::{http::header::{ContentDisposition, ContentType, CONTENT_DISPOSITION}, web, HttpResponse, Responder};
use chrono::{Months, NaiveDate, NaiveTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::PgPool;

use crate::models::{Availabillity, Function, Role, User};

#[derive(Deserialize)]
struct ExportQuery {
    year: u16,
    month: u8,
    area_id: Option<i32>,
    format: String
}

#[derive(Serialize)]
struct Export {
    year: u16,
    month: u8,
    area: String,
    availabillities: Vec<ExportAvailabillity>,
}

#[derive(Serialize)]
struct ExportAvailabillity {
    name: String,
    area: String,
    function: Function,
    date: NaiveDate,
    whole_day: bool,
    start_time: NaiveTime,
    end_time: NaiveTime,
    assigned: bool,
}

#[actix_web::get("/export/availabilitydata")]
pub async fn get(
    pool: web::Data<PgPool>,
    user: Identity,
    query: web::Query<ExportQuery>,
) -> impl Responder {
    // TODO: rerwrite
    let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
        .await
        .unwrap().unwrap();

    if current_user.role != Role::Admin && current_user.role != Role::AreaManager {
        return HttpResponse::Unauthorized().finish();
    }

    let start_date = NaiveDate::from_ymd_opt(query.year as i32, query.month as u32, 1)
        .unwrap_or(Utc::now().date_naive());
    let end_date = start_date
        .checked_add_months(Months::new(1))
        .unwrap()
        .pred_opt()
        .unwrap();

    let area_id = if current_user.role == Role::Admin && query.area_id.is_some() {
        query.area_id.unwrap()
    } else {
        current_user.area_id
    };

    let availabillities =
        Availabillity::read_for_export(pool.get_ref(), (start_date, end_date), area_id)
            .await
            .unwrap();

    let export_availabillities = availabillities
        .into_iter()
        .map(|a| ExportAvailabillity {
            name: a.user.as_ref().unwrap().name.clone(),
            area: a.user.as_ref().unwrap().area.as_ref().unwrap().name.clone(),
            function: a.user.unwrap().function,
            date: a.date,
            whole_day: a.start_time.is_none() && a.end_time.is_none(),
            start_time: a
                .start_time
                .unwrap_or(NaiveTime::from_hms_opt(0, 0, 0).unwrap()),
            end_time: a
                .end_time
                .unwrap_or(NaiveTime::from_hms_opt(23, 59, 59).unwrap()),
            assigned: false,
        })
        .collect();

    let export = Export {
        year: query.year,
        month: query.month,
        area: area_id.to_string(),
        availabillities: export_availabillities,
    };

    let out = match query.format.as_str() {
        "xml" => quick_xml::se::to_string(&export).unwrap_or(String::new()),
        "json" => serde_json::to_string(&export).unwrap_or(String::new()),
        _ => return HttpResponse::BadRequest().finish()
    };

    if !out.is_empty() {
        return HttpResponse::Ok()
            .content_type(ContentType::xml())
            .insert_header((CONTENT_DISPOSITION, ContentDisposition::attachment(format!("export.{}", query.format))))
            .body(out);
    }

    HttpResponse::BadRequest().finish()
}
