use std::collections::HashMap;

use chrono::{Datelike, NaiveDate};
use reqwest::Client;
use scraper::{Html, Selector};

use crate::{api::Meal, parser::utils::parse_french_date};

pub async fn get_available_meals(
    session: &str,
    filter_selected: bool,
    include_disabled: bool,
) -> Result<Vec<Meal>, Box<dyn std::error::Error>> {
    let url = "https://bjcolle.fr/no_waste.php";
    let response = Client::new()
        .get(url)
        .header("Cookie", session)
        .send()
        .await?
        .text()
        .await?;

    let document = Html::parse_document(&response);

    // Select each table row
    let row_selector = Selector::parse("#Choix > table > tbody > tr").unwrap();
    let label_selector = Selector::parse("label").unwrap();
    let input_selector = Selector::parse("input[type=\"checkbox\"]").unwrap();

    let mut meals = Vec::new();

    for row in document.select(&row_selector) {
        // Extract the label text (meal name)
        if let Some(label) = row.select(&label_selector).next() {
            let meal_name = label
                .text()
                .collect::<Vec<_>>()
                .join(" ")
                .trim()
                .to_string();

            // Extract the input checkbox
            if let Some(input) = row.select(&input_selector).next() {
                let is_checked = input.value().attr("checked").is_some();

                // Apply filtering: if filter_selected = true, skip unchecked
                if filter_selected && !is_checked {
                    continue;
                }

                let is_enabled = input.value().attr("disabled").is_none();
                if !is_enabled && !include_disabled {
                    continue;
                }

                if !meal_name.is_empty() {
                    if let Some(meal) = parse_meal(&meal_name) {
                        meals.push(meal);
                    }
                }
            }
        }
    }

    Ok(meals)
}

pub fn parse_meal(name: &str) -> Option<Meal> {
    // Normalize input
    let trimmed = name.trim();

    // Detect meal type
    let meal_type = if trimmed.starts_with("Déjeuner") {
        "lunch"
    } else if trimmed.starts_with("Dîner") {
        "dinner"
    } else {
        return None; // Unknown meal type
    }
    .to_string();

    // Extract date string (after "du ") and format it YYYY-MM-DD
    let date_part = trimmed.splitn(2, "du ").nth(1)?;
    let date = parse_french_date(date_part).unwrap();
    let date = date.format("%Y-%m-%d").to_string();

    Some(Meal { date, meal_type })
}

// Map chrono weekday to French first letter
fn french_day_letter(date: NaiveDate) -> char {
    match date.weekday() {
        chrono::Weekday::Mon => 'l', // Lundi
        chrono::Weekday::Tue => 'm', // Mardi
        chrono::Weekday::Wed => 'm', // Mercredi
        chrono::Weekday::Thu => 'j', // Jeudi
        chrono::Weekday::Fri => 'v', // Vendredi
        chrono::Weekday::Sat => 's', // Samedi
        chrono::Weekday::Sun => 'd', // Dimanche
    }
}

// Map chrono month to French month name
fn french_month(month: u32) -> &'static str {
    match month {
        1 => "janvier",
        2 => "février",
        3 => "mars",
        4 => "avril",
        5 => "mai",
        6 => "juin",
        7 => "juillet",
        8 => "août",
        9 => "septembre",
        10 => "octobre",
        11 => "novembre",
        12 => "décembre",
        _ => "",
    }
}

pub async fn submit_meals(meals: &[Meal], session: &str) -> Result<(), Box<dyn std::error::Error>> {
    let url = "https://bjcolle.fr/no_waste.php";
    let client = Client::new();

    let mut form: HashMap<String, String> = HashMap::new();

    // Mandatory field
    form.insert(
        "VALIDER_CHOIX".to_string(),
        "Valider+(même+si+rien+n'est+coché)".to_string(),
    );

    for meal in meals {
        let meal_date = NaiveDate::parse_from_str(&meal.date, "%Y-%m-%d")?;
        let day_letter = french_day_letter(meal_date);

        let key = match meal.meal_type.as_str() {
            "lunch" => format!("{}m", day_letter),  // midi
            "dinner" => format!("{}s", day_letter), // soir
            other => {
                eprintln!("Unknown meal_type: {}", other);
                continue;
            }
        };

        // Format like "30+août"
        let value = format!("{}+{}", meal_date.day(), french_month(meal_date.month()));

        form.insert(key, value);
    }

    let res = client
        .post(url)
        .header("Cookie", session)
        .form(&form)
        .send()
        .await?;

    if !res.status().is_success() {
        eprintln!("Failed to submit meals: HTTP {}", res.status());
        eprint!("Response: {:?}", res.text().await?);
        return Err("Failed to submit meals".into());
    }

    Ok(())
}
