use std::time::Duration;
use std::thread;
use std::fs::File;
use std::io::BufReader;
use rodio::{Decoder, OutputStream, Sink};
use std::sync::Mutex;
use once_cell::sync::Lazy;
use std::path::{Path, PathBuf};

use crate::serial;

struct Timings {
    charging_start_delay: u64,
    charging_delay: u64,
    charging_end_delay: u64,
}

static TIMINGS: Mutex<Lazy<Timings>> = Mutex::new(Lazy::new(|| Timings { charging_start_delay: 1600, charging_delay: 450, charging_end_delay: 400 } ));
static PLAYING: Mutex<bool> = Mutex::new(false);
pub static AUDIO_PATH: Mutex<Lazy<PathBuf>> = Mutex::new(Lazy::new(|| Path::new("assets/audio.mp3").to_path_buf()));

#[tauri::command]
pub fn start() {
    let mut playing = PLAYING.lock().unwrap();

    if *playing {
        return;
    } else {
        *playing = true;
    }
    thread::spawn(move || {
        println!("Starting animation...");


        play_sound();
        thread::sleep(Duration::from_millis(500));

        let _ = serial::write_serial(format!("SET_LIGHT:0;").as_str());
        stage_one();
        stage_two();

        let mut playing = PLAYING.lock().unwrap();
        *playing = false;
    });
}

fn play_sound() {
    thread::spawn(|| {
        let (_stream, stream_handle) = OutputStream::try_default().unwrap();
        let sink = Sink::try_new(&stream_handle).unwrap();

        let path = AUDIO_PATH.lock().unwrap();

        let file = BufReader::new(File::open(&**path).unwrap());
        let source = Decoder::new(file).unwrap();

        sink.append(source);

        sink.sleep_until_end();
    });
}

fn stage_one() {
    let timings = TIMINGS.lock().unwrap();

    thread::sleep(Duration::from_millis(timings.charging_start_delay));

    for i in 0..17 {
        let _ = serial::write_serial(format!("SET_LED:{},0,128,255;", i).as_str());
        let _ = serial::write_serial(format!("SET_LED:{},0,128,255;", 33 - i).as_str());

        let _ = serial::write_serial(format!("SET_LED:{},0,128,255;", i + 34).as_str());
        let _ = serial::write_serial(format!("SET_LED:{},0,128,255;", 67 - i).as_str());

        thread::sleep(Duration::from_millis(timings.charging_delay));
    }
}

fn stage_two() {
    let timings = TIMINGS.lock().unwrap();

    thread::sleep(Duration::from_millis(timings.charging_end_delay));
    let _ = serial::write_serial(format!("SET_LED_OFF;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,0,0;").as_str());

    thread::sleep(Duration::from_millis(200));
    let _ = serial::write_serial(format!("SET_LED_COLOR:0,128,255;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,128,255;").as_str());

    thread::sleep(Duration::from_millis(100));
    let _ = serial::write_serial(format!("SET_LED_OFF;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,0,0;").as_str());

    thread::sleep(Duration::from_millis(200));
    let _ = serial::write_serial(format!("SET_LED_COLOR:0,128,255;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,128,255;").as_str());

    thread::sleep(Duration::from_millis(200));
    let _ = serial::write_serial(format!("SET_LED_OFF;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,0,0;").as_str());

    thread::sleep(Duration::from_millis(100));
    let _ = serial::write_serial(format!("SET_LED_COLOR:0,128,255;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,128,255;").as_str());

    thread::sleep(Duration::from_millis(100));
    let _ = serial::write_serial(format!("SET_LED_OFF;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,0,0;").as_str());

    thread::sleep(Duration::from_millis(300));
    let _ = serial::write_serial(format!("SET_LED_COLOR:0,128,255;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,128,255;").as_str());

    thread::sleep(Duration::from_millis(100));
    let _ = serial::write_serial(format!("SET_LED_OFF;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,0,0;").as_str());

    thread::sleep(Duration::from_millis(100));
    let _ = serial::write_serial(format!("SET_LED_COLOR:0,128,255;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,128,255;").as_str());

    thread::sleep(Duration::from_millis(200));
    let _ = serial::write_serial(format!("SET_LED_OFF;").as_str());
    let _ = serial::write_serial(format!("SET_STRIP_COLOR:0,0,0;").as_str());
}
