use std::{
    collections::HashMap,
    fs::File,
    io::{Read, Write},
    path::{Path, PathBuf},
    sync::{Arc, OnceLock},
    time::Instant,
};

use chrono::Local;
use eframe::egui::{mutex::RwLock, vec2, Button, ProgressBar, TextEdit};
use egui::Context;
use egui_flex::{item, Flex};
use rfd::FileDialog;

use super::{
    activities::{activities, partnered_act, selected_act},
    generating::{data, generate, Schedule},
    limitations::limitations_ui::{
        classes_sched, create_classes_sched, create_teachers_sched, schedules, teachers_scheds,
    },
    print_pdf::{classes::classes_prints, teachers::teachers_prints},
};
pub fn params_hour() -> &'static RwLock<String> {
    static PARAM: OnceLock<RwLock<String>> = OnceLock::new();
    PARAM.get_or_init(|| RwLock::new("".to_string()))
}
pub fn total_hours() -> &'static RwLock<f32> {
    static PARAM: OnceLock<RwLock<f32>> = OnceLock::new();
    PARAM.get_or_init(|| RwLock::new(create_total_hours()))
}
pub fn create_total_hours() -> f32 {
    activities()
        .read()
        .clone()
        .values()
        .filter(|a| partnered_act().read().get(&a.id).is_none())
        .fold(0., |acc, x| acc + x.hour as f32)
}
pub fn continued() -> &'static RwLock<bool> {
    static PARAM: OnceLock<RwLock<bool>> = OnceLock::new();
    PARAM.get_or_init(|| RwLock::new(false))
}

pub fn generating() -> &'static Arc<RwLock<bool>> {
    static GENERATING: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
    GENERATING.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn multi_thread() -> &'static Arc<RwLock<bool>> {
    static GENERATING: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
    GENERATING.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn recalc_sched() -> HashMap<i32, Vec<Schedule>> {
    let schdls = &*schedules().read();
    let mut map: HashMap<i32, Vec<Schedule>> = HashMap::new();
    for s in schdls {
        let acts = activities().read();
        if let Some(a) = acts.get(&s.activity) {
            if let Some(tt) = map.get_mut(&a.id) {
                tt.push(s.clone());
            } else {
                map.insert(a.id, vec![s.clone()]);
            };
        };
    }
    map
}
pub fn generate_ui(ui: &mut eframe::egui::Ui) {
    ui.vertical_centered(|ui| {
        ui.add_sized(
            vec2(400., 30.),
            TextEdit::singleline(&mut *params_hour().write())
                .hint_text("Bir öğretmenin aynı sınıfa verebileceği ders saati sayısı"),
        );
        ui.add_space(10.);
        ui.add(
            ProgressBar::new(schedules().read().len() as f32 / *total_hours().read())
                .desired_width(400.)
                .desired_height(50.)
                .text(format!(
                    "                                                            {}/{}",
                    schedules().read().len(),
                    total_hours().read()
                ))
                .animate(*continued().read())
                .corner_radius(5),
        );
        ui.add_space(10.);
        if *generating().read() {
            if ui
                .add_sized(vec2(400., 30.), Button::new("Durdur"))
                .clicked()
            {
                *generating().write() = false;
            }
        } else {
            if *continued().read() {
                if ui
                    .add_sized(vec2(400., 30.), Button::new("Devam Et"))
                    .clicked()
                {
                    *generating().write() = true;
                    // *continued().write() = true;
                    generate();
                }
            } else {
                if ui
                    .add_sized(vec2(400., 30.), Button::new("Çalıştır"))
                    .clicked()
                {
                    *generating().write() = true;
                    *continued().write() = true;
                    generate();
                };
            }
        }
        if ui
            .add_sized(vec2(400., 30.), Button::new("Sıfırla"))
            .clicked()
        {
            let mut sch = vec![];
            data()
                .write()
                .timetables
                .retain(|_id, tt| tt.iter().any(|t| t.locked));
            data()
                .read()
                .timetables
                .values()
                .for_each(|tt| sch.append(&mut tt.clone()));
            *schedules().write() = sch.clone();
            *teachers_scheds().write() = create_teachers_sched();
            *classes_sched().write() = create_classes_sched();
            *total_hours().write() = create_total_hours();
        }
        // ui.allocate_space(ui.available_size());
        // ui.checkbox(&mut *multi_thread().write(), "Çoklu Thread Kullan");
        ui.layout().horizontal_justify();
        Flex::horizontal()
            .wrap(true)
            .width_percent(1.)
            .grow_items(1.)
            .show(ui, |flex| {
                flex.add_ui(item(), |ui| {
                    if ui
                        .add_sized(vec2(197., 30.), Button::new("Sınıf Programını Yazdır"))
                        .clicked()
                    {
                        classes_prints();
                    }
                    if ui
                        .add_sized(vec2(197., 30.), Button::new("Öğretmen Programını Yazdır"))
                        .clicked()
                    {
                        teachers_prints();
                    }
                });
            });
        ui.label(format!("{:?}", *selected_act().read()));
        if ui
            .add_sized(vec2(197., 30.), Button::new("Programı Kaydet"))
            .clicked()
        {
            save_scheds();
        }
        if ui
            .add_sized(vec2(197., 30.), Button::new("Programı Aç"))
            .clicked()
        {
            open_scheds();
        }
    });
}
pub fn save_scheds() {
    std::thread::spawn(move || {
        let scheds = &*schedules().read();
        let js = serde_json::to_string(&*scheds.clone());
        match js {
            Ok(j) => {
                let date = Local::now();
                let file_name = format!("./db/scheds/{}.json", date.format("%Y-%m-%d %H:%M"));
                let mut f = File::create(file_name).unwrap();
                f.write_all(j.as_bytes()).unwrap();
            }
            Err(_) => {}
        }
    });
}
pub fn read_scheds(path: PathBuf) {
    std::thread::spawn(move || {
        let f = File::open(path);
        if let Ok(mut f) = f {
            let mut content: String = String::new();
            f.read_to_string(&mut content).unwrap();
            let cls: Vec<Schedule> = serde_json::from_str(content.as_str()).unwrap();
            let data = &mut *data().write();
            let tt = &mut data.timetables;
            for sch in &cls {
                tt.entry(sch.activity)
                    .and_modify(|a| a.push(sch.clone()))
                    .or_insert(vec![sch.clone()]);
            }
            *schedules().write() = cls;
        }
    });
}
pub fn open_scheds() {
    let file = FileDialog::new()
        .set_title("Dosya Seç")
        .set_directory("./db/scheds")
        .pick_file();
    read_scheds(file.unwrap());
}