mod polygon_draw;
use iced::keyboard::Modifiers;
use polygon_draw::Polygon;

mod music;
use music::Music;

mod message;
use message::Message;

mod utils;
use utils::{delta_to_string, is_delta_format_valid, str_to_sec};

use std::fs;

mod gui;
use gui::{load_file_view, music_view};

use iced::Font;
use iced::Theme;
use iced::{
    Color, Event, Task,
    event::{self, Status},
    keyboard::{Key, key::Named},
};

use std::time::Instant;

use kira::{
    AudioManager, AudioManagerSettings, DefaultBackend, sound::static_sound::StaticSoundData,
};
const FONT_BYTES: &[u8] = include_bytes!("../fonts/EnvyCodeRNerdFontMono-Regular.ttf");
const FONT: Font = Font::with_name("EnvyCodeR Nerd Font Mono");

fn main() -> iced::Result {
    let polytheme: Theme = {
        let back = Color::from_rgb8(39, 63, 79);
        let text = Color::from_rgb8(0xD3, 0xD4, 0xD9);
        let prim = Color::from_rgb8(230, 82, 31);
        let succ = Color::from_rgb8(0xFF, 0xF9, 0xFB);
        let dan = Color::from_rgb8(0xBB, 0x0A, 0x21);

        Theme::custom(
            String::from("PolyTheme"),
            iced::theme::Palette {
                background: back,
                text: text,
                primary: prim,
                success: succ,
                danger: dan,
            },
        )
    };
    iced::application("My App", MyApp::update, MyApp::view)
        .theme(move |_| polytheme.clone())
        .font(iced_fonts::REQUIRED_FONT_BYTES)
        .font(FONT_BYTES)
        .default_font(FONT)
        .antialiasing(true)
        .subscription(MyApp::subscription)
        .run_with(MyApp::new)
}

struct MyApp {
    music: Music,
    time_last_frame: Instant,
    paused: bool,
    audio_manager: AudioManager,
    all_sounds: Vec<String>,
    all_saves: Vec<String>,
    current_delta: f32,
    str_music_length: String,
    str_time: String,
    can_unpaused: bool,
    already_save: bool,
    mode_file_load: bool,
    file_name_to_creat: String,
    show_warning_message_creat: bool,
}

impl MyApp {
    fn new() -> (Self, Task<Message>) {
        let manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())
            .expect("Error to load AudioManager");

        //let font_bytes = include_bytes!("../fonts/");

        (
            Self {
                time_last_frame: Instant::now(),
                audio_manager: manager,
                paused: true,
                all_sounds: load_path_sounds(),
                all_saves: load_path_saves(),
                music: Music::default(),
                current_delta: 0.0,
                str_music_length: "01:00:00".to_string(),
                str_time: "00:00:00".to_string(),
                can_unpaused: true,
                already_save: true,
                mode_file_load: true,
                file_name_to_creat: "Default File Name".to_string(),
                show_warning_message_creat: false,
            },
            Task::none(),
        )
    }
    fn update(&mut self, message: Message) {
        match message {
            Message::AddPolygon(s) => {
                self.music.add_polygon(self.current_delta, s);
                self.already_save = false;
            }
            Message::Tick => {
                if self.current_delta >= self.music.length {
                    self.paused = true
                }
                if !self.paused {
                    self.music.current_delta = self.current_delta;
                    let time_btw = Instant::now().duration_since(self.time_last_frame);
                    self.current_delta += time_btw.as_millis() as f32 / 1000.0;
                    self.music
                        .apply_tick(self.current_delta, time_btw, &mut self.audio_manager);
                    self.time_last_frame = Instant::now();
                    self.str_time = delta_to_string(self.current_delta);
                }
            }
            Message::Remove(i) => {
                self.music.remove_polygon(self.current_delta, i);
                self.already_save = false;
            }
            Message::ChangeTeta(i, teta) => {
                self.music.set_teta(self.current_delta, i, teta);
                self.already_save = false;
            }

            Message::ChangeSound(i, s) => {
                let sound = StaticSoundData::from_file(format!("./assets/{s}"))
                    .expect("Fail to load audio");
                self.music.set_sound(self.current_delta, i, sound, s);
                self.already_save = false;
            }
            Message::Save => {
                let json = serde_json::to_string_pretty(&self.music).unwrap();
                fs::write(format!("./saves/{0}.pmx", &self.music.file_name), json).unwrap();
                self.all_saves = load_path_saves();
                self.already_save = true;
            }
            Message::Load => {
                let json = fs::read_to_string(format!("./saves/{0}.pmx", &self.music.file_name));
                match json {
                    Ok(j) => {
                        let decoded: Music = serde_json::from_str(&j).unwrap();
                        self.music = decoded;
                        self.music.update_frame();
                        self.mode_file_load = false;
                    }
                    Err(e) => {
                        eprintln!("Error, no saves with this name to load, {e} ");
                    }
                }
            }
            Message::SetFileNameCreat(s) => self.file_name_to_creat = s,
            Message::CreatFile => {
                if self.all_saves.contains(&self.file_name_to_creat) {
                    self.show_warning_message_creat = true;
                } else {
                    self.mode_file_load = false;
                    self.music = Music::default();
                    self.music.file_name = self.file_name_to_creat.clone();
                    self.update(Message::Save);
                }
            }
            Message::FileNameChanged(s) => self.music.file_name = s,
            Message::LengthChange(s) => {
                if is_delta_format_valid(&s) {
                    let sec = str_to_sec(&s);
                    if sec > 0. {
                        self.music.length = sec;
                        self.already_save = false;
                    }
                }
                self.str_music_length = s;
            }
            Message::TogglePaused => {
                self.paused = !self.paused;
                if !self.paused {
                    self.time_last_frame = Instant::now();
                }
            }

            Message::ChangeDelta(f) => {
                self.current_delta = f;
                self.music.fix_teta(self.current_delta);
                // update the red dot on canvas
                self.update_canvas_if_paused();
            }
            Message::ChangeDeltaString(s) => {
                if is_delta_format_valid(&s) {
                    self.already_save = false;
                    self.update(Message::ChangeDelta(str_to_sec(&s)));
                }
                self.str_time = s;
            }
            Message::AddPoint => {
                self.already_save = false;
                self.music.add_point(self.current_delta);
            }
            Message::RemovePoint => {
                self.already_save = false;
                self.music.remove_point(self.current_delta);
            }
            Message::ClickedOnTimeLine(f) => {
                self.update(Message::ChangeDelta(f));
            }
            Message::SlidePointLeft => {
                self.already_save = false;
                self.music.slide_to_left(self.current_delta);
                self.music.fix_teta(self.current_delta);
                self.update_canvas_if_paused();
            }
            Message::SlidePointRight => {
                self.already_save = false;
                self.music.slide_to_right(self.current_delta);
                self.music.fix_teta(self.current_delta);
                self.update_canvas_if_paused();
            }
            Message::ChangeDegree(i, s) => {
                let mut mut_s = s;
                if mut_s.len() == 0 {
                    mut_s = "0".to_string();
                }
                match mut_s.parse::<f32>() {
                    Ok(val) => {
                        if val >= 0. && val <= 360. {
                            self.update(Message::ChangeTeta(i, (val).to_radians()));
                            self.already_save = false;
                        }
                    }
                    Err(_) => {}
                }
            }
            Message::ChangeNbPerSec(s) => {
                let mut_s = s.trim_end_matches(" sec/rev");
                if mut_s.len() != s.len() {
                    match mut_s.parse::<f32>() {
                        Ok(val) => {
                            let val = (val * 10.).floor() / 10.;
                            if val >= 1. && val < 1000. {
                                self.music.nb_sec_for_rev = val;
                                self.already_save = false;
                            }
                        }
                        Err(_) => {}
                    }
                }
            }
            Message::CancelColor(i) => {
                self.music.set_color_picker(self.current_delta, i, false);
                self.can_unpaused = true;
            }
            Message::SubmitColor(i) => {
                if !self.paused {
                    self.update(Message::TogglePaused);
                }
                self.can_unpaused = false;
                self.music.set_color_picker(self.current_delta, i, true);
            }
            Message::ChooseColor(i, color) => {
                self.music.set_color(self.current_delta, i, color);
                self.music.set_color_picker(self.current_delta, i, false);
                self.can_unpaused = true;
                self.already_save = false;
            }
            Message::None => {}
            Message::GoToLoadView => {
                if self.already_save {
                    self.paused = true;
                    self.file_name_to_creat = "Default File Name".to_string();
                    self.show_warning_message_creat = false;
                    self.mode_file_load = true
                }
            }
            Message::ForceToQuit => {
                self.already_save = true;
            }
        }
    }

    fn view(&self) -> iced::Element<Message> {
        if !self.mode_file_load {
            music_view(self)
        } else {
            load_file_view(self)
        }
    }

    fn subscription(&self) -> iced::Subscription<Message> {
        let subscr_key = event::listen_with(|event, status, _| match (event, status) {
            (
                Event::Keyboard(iced::keyboard::Event::KeyPressed {
                    key: Key::Character(c),
                    modifiers: Modifiers::CTRL,
                    ..
                }),
                Status::Ignored,
            ) if c.as_ref() == "s" => Some(Message::Save),
            (
                Event::Keyboard(iced::keyboard::Event::KeyPressed {
                    key: Key::Named(Named::Space),
                    ..
                }),
                Status::Ignored,
            ) => Some(Message::TogglePaused),
            (
                Event::Keyboard(iced::keyboard::Event::KeyPressed {
                    key: Key::Named(Named::ArrowUp),
                    ..
                }),
                Status::Ignored,
            ) => Some(Message::ChangeDelta(0.0)),
            (
                Event::Keyboard(iced::keyboard::Event::KeyPressed {
                    key: Key::Character(c),
                    modifiers: Modifiers::CTRL,
                    ..
                }),
                Status::Ignored,
            ) if c.as_ref() == "f" => Some(Message::ForceToQuit),

            _ => None,
        });
        if self.paused {
            subscr_key
        } else {
            iced::Subscription::batch([
                subscr_key,
                iced::time::every(std::time::Duration::from_millis(16)).map(|_| Message::Tick),
            ])
        }
    }

    fn update_canvas_if_paused(&mut self) {
        if self.paused {
            self.update(Message::TogglePaused);
            self.update(Message::Tick);
            self.update(Message::TogglePaused);
        }
    }
}

fn load_path_sounds() -> Vec<String> {
    let mut entries: Vec<String> = fs::read_dir("./assets")
        .unwrap()
        .filter_map(|res| res.ok())
        .map(|e| e.path().file_name().unwrap().to_str().unwrap().to_string())
        .collect();
    entries.sort();
    entries
}

fn load_path_saves() -> Vec<String> {
    fs::create_dir_all("./saves").expect("fail to creat 'saves' !");
    let mut saves: Vec<String> = fs::read_dir("./saves")
        .unwrap()
        .filter_map(|res| res.ok())
        .map(|e| {
            e.path()
                .file_name()
                .unwrap()
                .to_str()
                .unwrap()
                .trim_end_matches(".pmx")
                .to_string()
        })
        .collect();
    saves.sort();
    saves
}
