use std::ops::Deref;
use std::sync::{Arc};
use chrono::{Duration, Local};
use tokio::sync::{RwLock, RwLockReadGuard};
use tokio::time::sleep;
use crate::{SharedData};
use crate::post_history::{PostHistory, PostHistoryInner};

pub(crate) async fn run<'a>(shared_data: Arc<RwLock<SharedData>>) {
    let mut min_len_series: u32 = 0;
    let mut min_len_slug: u32 = 0;
    println!("TUI restarted");
    loop {
        let snapshot_data = shared_data.read().await;
        sleep(Duration::milliseconds(250).to_std().unwrap()).await;
        print_info(snapshot_data, &mut min_len_series, &mut min_len_slug).await;
    }
}

async fn print_info<'a>(data: RwLockReadGuard<'a, SharedData>, min_len_series: &mut u32, min_len_slug: &mut u32) {
    let mut local_min_len_series = *min_len_series.deref() as usize;
    let mut local_min_len_slug = *min_len_slug.deref() as usize;
    let separator_width = local_min_len_slug + local_min_len_series + 44; // 44 should account for length of every other string

    print!("\x1B[2J\x1B[1;1H");
    println!(
        "##[Ascendance of a Bookworm Bot]## | Time: {}",
        Local::now().naive_local().format("%H:%M:%S")
    );
    println!("Instance: {}", data.config.instance);
    println!(
        "Ran Last: {} | Config Reload Interval: {}",
        data
            .start
            .with_timezone(&Local)
            .naive_local()
            .format("%d/%m/%Y %H:%M:%S"),
        data.config.config_reload_seconds
    );
    println!("{:#<1$}", "", separator_width);
    let mut sorted_series: Vec<(&String, &PostHistory)> = data.post_history.series.iter().collect();
    sorted_series.sort_by(|(a, _), (b, _)| a.cmp(b));
    sorted_series.iter().for_each(|(series, post_history)| {

        if series.len() > local_min_len_series {
            local_min_len_series = series.len() + 1;
            *min_len_series = local_min_len_series as u32;
        }

        let series_config = data.config.series
            .iter()
            .find(|ser| {&&ser.slug == series})
            .expect("Config should not parse without this");
        let mut sorted_parts: Vec<(&String, &PostHistoryInner)> = post_history.parts.iter().collect();
        sorted_parts.sort_by(|(a, _), (b, _)| a.cmp(b));
        sorted_parts.iter().for_each(|(part, part_history)| {

            if part_history.volume.len() > local_min_len_slug {
                local_min_len_slug = part_history.chapter.len() + 1;
                *min_len_slug = local_min_len_slug as u32;
            }

            print!("{series}");
            print!("{:<1$}| ", "", local_min_len_series - series.len());
            print!("Part {part}");
            print!("{:<1$}| Volume  | ", "", 2-part.len());
            print!("{}", part_history.volume);
            print!("{:<1$}| ", "", local_min_len_slug - part_history.volume.len());
            print!("{}", series_config.volume_community.name);
            println!("{:<1$}|", "", 20 - series_config.volume_community.name.len());

            if part_history.chapter.len() > local_min_len_slug {
                local_min_len_slug = part_history.chapter.len() + 1;
                *min_len_slug = local_min_len_slug as u32;
            }

            print!("{series}");
            print!("{:<1$}| ", "", local_min_len_series - series.len());
            print!("Part {part}");
            print!("{:<1$}| Chapter | ", "", 2-part.len());
            print!("{}", part_history.chapter);
            print!("{:<1$}| ", "", local_min_len_slug - part_history.chapter.len());
            print!("{}", series_config.prepub_community.name);
            println!("{:<1$}|", "", 20 - series_config.prepub_community.name.len());
        });
    });
    println!("{:#<1$}", "", separator_width);
    for error in data.get_messages(true, true, false).iter() {
        println!("{}", error.content());
    }
    println!("{:#<1$}", "", separator_width);
    for message in data.get_messages(false, false, true).iter() {
        println!("{}", message.content());
    }
}