use chrono::NaiveDateTime;
use reqwest::{self, Client};
use serde_json::json;

use crate::configuration::{Settings, get_config};

pub async fn post_colle(
    colle: &Colle,
    class_name: &str,
    config: &Settings,
) -> Result<(), Box<dyn std::error::Error>> {
    let api_url = get_config(config, "api");
    let api_token = get_config(config, "token");

    let url = format!("{api_url}/colles");
    let colle_json = json!({
        "colle": &colle,
        "className": class_name,
    });

    let response = Client::new()
        .post(&url)
        .json(&colle_json)
        .header("Content-Type", "application/json")
        .header("Accept", "application/json")
        // Bearer token for authentication
        .header("Authorization", format!("Bearer {api_token}"))
        .send()
        .await?;
    // Check if the response is successful
    if !response.status().is_success() {
        eprintln!("Failed to post colle: HTTP {}", response.status(),);
        eprint!("Response: {:?}", response.text().await?);
        return Err("Failed to post colle".into());
    }

    Ok(())
}

pub async fn post_upcoming_colles(
    colles: &[Colle],
    class_name: &str,
    config: &Settings,
) -> Result<(), Box<dyn std::error::Error>> {
    let api_url = get_config(config, "api");
    let api_token = get_config(config, "token");

    let url = format!("{api_url}/colles/upcoming");
    let colles_json = json!({
        "colles": &colles,
        "className": class_name,
    });

    let response = Client::new()
        .post(&url)
        .json(&colles_json)
        .header("Content-Type", "application/json")
        .header("Accept", "application/json")
        // Bearer token for authentication
        .header("Authorization", format!("Bearer {api_token}"))
        .send()
        .await?;

    let status = response.status();
    
    // Check if the response is successful
    if !status.is_success() {
        let body = response.text().await?;
        eprintln!("❌ Failed to post colle");
        eprintln!("   → URL: {url}");
        eprintln!("   → Status: {status}");
        eprintln!("   → Request body: {colles_json}");
        eprintln!("   → Response body: {body}");
        return Err("Failed to post upcoming colles".into());
    }

    Ok(())
}

pub async fn post_submittable_meals(
    meals: &[Meal],
    config: &Settings,
) -> Result<(), Box<dyn std::error::Error>> {
    let api_url = get_config(config, "api");
    let api_token = get_config(config, "token");

    let url = format!("{api_url}/meals");
    let meals_json = json!({
      "meals": &meals
    });
    println!("Posting submittable meals: {:?}", meals_json);

    let response = Client::new()
        .post(&url)
        .json(&meals_json)
        .header("Content-Type", "application/json")
        .header("Accept", "application/json")
        // Bearer token for authentication
        .header("Authorization", format!("Bearer {api_token}"))
        .send()
        .await?;
    // Check if the response is successful
    if !response.status().is_success() {
        eprintln!(
            "Failed to post submittable meals: HTTP {}",
            response.status(),
        );
        eprint!("Response: {:?}", response.text().await?);
        return Err("Failed to post submittable meals".into());
    }

    Ok(())
}

pub async fn post_selected_meals(
    meals: &[Meal],
    user_id: &i64,
    config: &Settings,
) -> Result<(), Box<dyn std::error::Error>> {
    let api_url = get_config(config, "api");
    let api_token = get_config(config, "token");

    let url = format!("{api_url}/internals/meals-registrations");
    let meals_json = json!({
        "meals": &meals,
        "userId": user_id,
    });

    let response = Client::new()
        .post(&url)
        .json(&meals_json)
        .header("Content-Type", "application/json")
        .header("Accept", "application/json")
        // Bearer token for authentication
        .header("Authorization", format!("Bearer {api_token}"))
        .send()
        .await?;
    // Check if the response is successful
    if !response.status().is_success() {
        eprintln!("Failed to post selected meals: HTTP {}", response.status(),);
        eprint!("Response: {:?}", response.text().await?);
        return Err("Failed to post selected meals".into());
    }

    Ok(())
}

#[derive(Debug, serde::Serialize)]
pub struct Colle {
    pub date: NaiveDateTime,
    pub examiner: String,
    pub room: String,
    pub subject: String,
    pub student: String,
    pub bjid: Option<String>,
    pub bjsecret: Option<String>,
    pub grade: Option<f32>,
    pub content: Option<String>,
    pub comment: Option<String>,
    pub attachments: Option<Vec<ColleAttachment>>, // (file_url, file_name)
}

#[derive(Debug, serde::Serialize)]
pub struct ColleAttachment {
    pub url: String,
    pub name: String,
}

#[derive(Debug, serde::Serialize)]
pub struct Meal {
    pub date: String, // "YYYY-MM-DD"
    pub meal_type: String, // "lunch" or "dinner"
}
