mod actions;
mod ui;

use client_shared::{LOGO, LOGO_DURATION};
use cursive::align::Align;
use cursive::view::Resizable as _;
use cursive::views::TextView;
use cursive::{event, Cursive};
use cursive::CursiveExt as _;
use std::ffi::OsString;
use std::str::FromStr;
use std::thread;
use std::time::Duration;

use ui::INPUT_FIELD_ID;

use client_shared::persistence::{Appdata, load_appdata, save_appdata};

pub fn get_appdata(siv: &mut Cursive) -> Appdata {
    siv.with_user_data(|appdata: &mut Appdata| appdata.clone())
        .expect("Failed to retrieve appdata.")
}

fn main() {
    if cfg!(debug_assertions) {
        logging::set_global_log_level(logging::LogLevel::Trace);
    } else {
        logging::set_global_log_level(logging::LogLevel::Debug);
    }

    logging::set_global_log_path(Some(OsString::from_str("./client-log.txt").unwrap()));

    utils::rng::shuffle_rng();

    let mut siv = Cursive::default();

    // TODO (low): Add a notice when the file is corrupted.
    let appdata = match load_appdata() {
        Ok(Some(x)) => x,
        _ => Appdata::new(),
    };

    siv.set_user_data(appdata);

    // Global hotkeys
    siv.add_global_callback(event::Key::Backspace, |siv| {
        let _ = siv.focus_name(INPUT_FIELD_ID);
    });

    // Logo intro screen
    siv.add_fullscreen_layer(TextView::new(LOGO).align(Align::center()).full_screen());

    // Background thread
    {
        let cb_sink = siv.cb_sink().clone();

        thread::spawn(move || {
            let mut timer = 0;

            loop {
                cb_sink
                    .send(Box::new(move |siv| {
                        let appdata = get_appdata(siv);

                        if appdata.intro_screen_shown_until > utils::time::time_millis() {
                            thread::sleep(Duration::from_millis(
                                appdata
                                    .intro_screen_shown_until
                                    .saturating_sub(utils::time::time_millis())
                                    as u64,
                            ));
                            // Main layout
                            let main_layout = ui::setup_ui(siv);
                            siv.pop_layer();
                            siv.add_fullscreen_layer(main_layout);
                        }

                        ui::visual_update(siv);

                        if timer % appdata.persistent_data.api_refresh_rate == 0 {
                            // TODO (low): Add a notice when automatic refresh fails.
                            let _ = actions::load_messages(siv);
                        }

                        save_appdata(get_appdata(siv));
                    }))
                    .expect("Failed to send callback from background thread.");

                timer += 1;
                thread::sleep(Duration::from_secs(1));
            }
        });
    }

    siv.with_user_data(|appdata: &mut Appdata| {
        appdata.intro_screen_shown_until = utils::time::time_millis() + LOGO_DURATION;
    });
    siv.run();
}
