#![allow(unused)]

use std::env;
use std::fs;
use std::{
    io::{BufRead, BufReader, Error, Read, Stdin, Stdout, Write},
    path::{Path, PathBuf},
    process::{Command, Stdio},
    thread::{self, sleep},
    time::{Duration, Instant},
};

use devices::get_devices;
use keys::create_password;
use rsa::Pkcs1v15Encrypt;
use rsa::RsaPrivateKey;

use crate::devices::list_devices;
use log::{debug, error, info, log_enabled, Level};
mod devices;
mod keys;
fn main() {
    env_logger::init();
    //env_logger::builder().format_level(write);
    let mut priv_key = keys::get_priv_key();
    let args: Vec<String> = env::args().collect();
    if let Some(arg) = args.get(1) {
        match arg.as_ref() {
            "-a" => {
                let mut devices = devices::get_devices();
                devices.retain(|d| d.is_mounted());
                list_devices(&devices);
                println!("Bir disk seçin");
                let mut buffer = String::new();
                std::io::stdin().read_line(&mut buffer).unwrap();
                let selected_disk = buffer.trim().parse::<usize>().unwrap();
                if selected_disk <= devices.len() {
                    let d = devices[selected_disk - 1].clone();
                    d.write_pub_key(&priv_key);
                }
                return ();
            }
            "-c" => {
                create_password(priv_key);
            }
            "-d" => {
                get_devices();
            }
            _ => {
                println!("invalid arg");
                return ();
            }
        }
    } else {
        start_loop(priv_key);
    }
}
fn start_loop(priv_key: rsa::RsaPrivateKey) {
    let schoold_id = env::var("SCHOOL_ID").unwrap_or("1".to_string());
    let mut lock_time = env::var("LOCK")
        .unwrap_or("240".to_string())
        .parse::<u64>()
        .unwrap_or(240);
    let mut rng = rand::thread_rng();
    let mut est_time = Instant::now();
    //let mut status_changed = false;
    let mut lock_state = LockState::Locked;
    loop {
        if est_time.elapsed().as_secs() >= lock_time && lock_state == LockState::Locked {
            shutdown();
        }
        match &lock_state {
            LockState::Locked => {
                log::info!("0 {}", lock_time - est_time.elapsed().as_secs());
                if !check_usb(&priv_key, &mut lock_state) {
                    check_key(&mut lock_state);
                }
            }
            LockState::Unlocked(unlock) => match unlock {
                UnlockedState::Usb(serial) => {
                    log::info!("1 0");
                    let devices = get_devices();
                    if !devices.iter().any(|d| &d.get_serial() == serial) {
                        lock_state = LockState::Locked;
                    }
                }
                UnlockedState::Key => {
                    log::info!("1 1");
                    thread::sleep(Duration::from_secs(60 * 40));
                    lock_time = 240;
                    est_time = Instant::now();
                }
            },
        }
        thread::sleep(Duration::from_millis(1000));
    }
}
fn check_usb(priv_key: &RsaPrivateKey, state: &mut LockState) -> bool {
    let mut devices = devices::get_devices();
    for device in &devices {
        if device.read_key(&priv_key.clone()) {
            *state = LockState::Unlocked(UnlockedState::Usb(device.get_serial()));
            return true;
        }
    }
    false
}
fn check_key(state: &mut LockState) -> bool {
    if confirm_key() {
        std::fs::remove_file("/tmp/kilit").unwrap_or_default();
        *state = LockState::Unlocked(UnlockedState::Key);
        return true;
    }
    false
}
fn confirm_key() -> bool {
    let school_id = env::var("SCHOOL_ID").unwrap_or("1".to_string());
    let key = std::fs::read_to_string("/tmp/kilit");
    if let Ok(key) = key {
        let agent: ureq::Agent = ureq::AgentBuilder::new()
            .timeout_read(Duration::from_secs(5))
            .timeout_write(Duration::from_secs(5))
            .build();
        let url = format!("https://etapkilit.libredu.org/confirm_key/{}", key);
        let body: u16 = agent.get(&url).call().unwrap().status();
        return body == 200;
    }
    // log::info!("confirm started3");
    false
}
fn shutdown() {
    let a = Command::new("shutdown")
        .arg("-h")
        .arg("now")
        .spawn()
        .unwrap();
}

#[derive(Debug, Clone, PartialEq)]
enum LockState {
    Locked,
    Unlocked(UnlockedState),
}
#[derive(Debug, Clone, PartialEq)]
enum UnlockedState {
    Usb(String),
    Key,
}