#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example

mod utils;

use std::{collections::HashSet, sync::mpsc::Receiver, time::Duration};

use eframe::egui::{
    self, vec2, Color32, FontId, FontSelection, Frame, Key, Layout, Margin, Modifiers, RichText,
    Rounding, ScrollArea, Stroke, TextEdit, TopBottomPanel, Ui, ViewportBuilder, ViewportId,
};
use egui_phosphor::regular::{APP_WINDOW, GEAR_SIX, VIDEO};
use evalexpr::eval;
use global_hotkey::{hotkey::HotKey, GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState};
use keyboard_types::Code;
use utils::{display_files, get_apps, spawn_app};

fn main() {
    let (tx, rx) = std::sync::mpsc::channel();
    let manager = GlobalHotKeyManager::new().unwrap();
    let hotkey = HotKey::new(Some(keyboard_types::Modifiers::CONTROL), Code::Space);

    manager.register(hotkey).unwrap();
    let receiver = GlobalHotKeyEvent::receiver();
    std::thread::spawn(move || loop {
        if let Ok(GlobalHotKeyEvent {
            id: _,
            state: HotKeyState::Pressed,
        }) = receiver.try_recv()
        {
            // println!("tray event: {event:?}");
            let _ = tx.send(());
        }
        std::thread::sleep(Duration::from_millis(10));
    });

    let native_options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            .with_inner_size([400.0, 300.0])
            .with_max_inner_size([600.0, 300.0])
            .with_decorations(false)
            .with_maximized(false)
            .with_active(true)
            // .with_always_on_top()
            .with_icon(
                // NOE: Adding an icon is optional
                eframe::icon_data::from_png_bytes(&include_bytes!("../assets/dog.png")[..])
                    .unwrap(),
            ),
        ..Default::default()
    };

    let _ = eframe::run_native(
        "anybar",
        native_options,
        Box::new(|cc| {
            let mut fonts = egui::FontDefinitions::default();
            egui_phosphor::add_to_fonts(&mut fonts, egui_phosphor::Variant::Regular);

            cc.egui_ctx.set_fonts(fonts);

            let mut a = Doo::new(cc, rx);
            a.app_list = get_apps().unwrap();
            a.app_set = HashSet::from_iter(a.app_list.iter().cloned());
            Box::new(a)
        }),
    );
}

#[derive(Default)]
enum BarMode {
    #[default]
    Normal,
    Calculator,
    WebSearch,
}

struct Doo {
    // If Doo is visible
    pub visible: bool,
    // The user search input
    pub search_input: String,
    // The mode of the bar
    pub mode: BarMode,
    // The filtered list cursor
    pub cursor: usize,
    // if loading
    pub loading: bool,
    // working scratch area when showing list of apps.
    app_list: Vec<String>,
    // the master app list
    app_set: HashSet<String>,
    // selected app
    selected_app: String,
    // listener for global hotkey events
    rx: Receiver<()>,
}

impl Doo {
    pub fn new(cc: &eframe::CreationContext<'_>, rx: Receiver<()>) -> Self {
        Self {
            search_input: String::new(),
            app_list: Vec::new(),
            app_set: HashSet::new(),
            cursor: 0,
            selected_app: String::new(),
            mode: BarMode::Normal,
            loading: false,
            // gradient_line: GradientLine::new(1.),
            // animated_frame: AnimatedFrame::new(),
            rx,
            visible: true,
        }
    }
    fn render_app_list(&mut self, ui: &mut Ui) {
        ScrollArea::vertical().id_source("app_list").show(ui, |ui| {
            for (i, app) in self
                .app_list
                .iter_mut()
                .filter(|a| a.contains(&self.search_input))
                .take(100)
                .enumerate()
            {
                ui.add_sized(vec2(ui.available_width(), 0.), |ui: &mut Ui| {
                    let mut f = Frame::default()
                        .inner_margin(Margin::same(6.))
                        .outer_margin(Margin::same(1.))
                        .rounding(Rounding::same(2.))
                        .fill(if i == self.cursor {
                            self.selected_app = app.to_string();
                            Color32::from_hex("#0F8B8D").unwrap()
                        } else {
                            Color32::from_rgba_unmultiplied(215, 218, 229, 4)
                        })
                        .show(ui, |ui: &mut Ui| {
                            ui.with_layout(Layout::left_to_right(egui::Align::Min), |ui| {
                                ui.heading(APP_WINDOW);
                                ui.separator();
                                let res = ui.vertical(|ui| {
                                    let rt = RichText::new(format!("{}{}", VIDEO, app))
                                        .color(Color32::WHITE);
                                    ui.horizontal(|ui| {
                                        ui.label(rt);
                                        ui.small_button("c");
                                        ui.small_button("shift");
                                        ui.small_button("x");
                                    });
                                    let mut rt = RichText::new("Do awesome things with this app")
                                        .color(Color32::WHITE);
                                    ui.small(rt);
                                });

                                // if i == self.cursor {
                                //     res.response.scroll_to_me(Some(egui::Align::Center));
                                // }
                            });
                            ui.with_layout(Layout::right_to_left(egui::Align::Max), |ui| {
                                ui.small("Application");
                            });

                            if ui.input_mut(|r| r.consume_key(Modifiers::NONE, Key::ArrowDown)) {
                                self.cursor = self.cursor.wrapping_add(1);
                                // dbg!(&self.selected_app);
                                // self.selected_app = app.clone();
                                // dbg!(&i);
                                dbg!(&self.selected_app);
                            }

                            if ui.input_mut(|r| r.consume_key(Modifiers::NONE, Key::ArrowUp)) {
                                self.cursor = self.cursor.wrapping_sub(1);
                                dbg!(&self.selected_app);
                                // ctx.set_zoom_factor(0.3);
                            }

                            if ui.input_mut(|r| r.consume_key(Modifiers::NONE, Key::Enter)) {
                                let _ = spawn_app(&self.selected_app);
                                self.visible = false;
                                ui.ctx().send_viewport_cmd(egui::ViewportCommand::Visible(
                                    self.visible,
                                ));
                            }
                        });

                    ui.small("")
                });
            }

            self.render_files(ui);
        });
    }

    fn render_files(&self, ui: &mut Ui) {
        ui.small("Files and folders");
        ui.separator();
        display_files(ui, "/home/creativcoder", &self.search_input);
    }
}

impl eframe::App for Doo {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default()
            .frame(Frame::default().fill(Color32::TRANSPARENT))
            .show(ctx, |ui| {
                let _app_frame = Frame::default()
                    .inner_margin(Margin::same(5.))
                    .stroke(Stroke::new(0.5, Color32::WHITE))
                    .rounding(Rounding::same(4.))
                    .fill(Color32::from_hex("#143642").unwrap())
                    .show(ui, |ui| {
                        ui.vertical_centered(|ui| {
                            ui.label("doo");

                            // search input
                            ui.add_sized(
                                vec2(ui.available_rect_before_wrap().width(), 32.),
                                |ui: &mut Ui| {
                                    let te = TextEdit::singleline(&mut self.search_input)
                                        .frame(true)
                                        .text_color(Color32::WHITE)
                                        .desired_width(ui.available_width())
                                        .vertical_align(egui::Align::Center)
                                        // .margin(Margin::same(2.))
                                        .font(FontSelection::FontId(FontId::proportional(11.)));
                                    // .hint_text(MAGNIFYING_GLASS);

                                    let edit_text = ui.add(te);

                                    if edit_text.changed() {
                                        if self.search_input.starts_with("1") {
                                            self.mode = BarMode::Calculator;
                                        } else if self.search_input.starts_with("/") {
                                            self.mode = BarMode::WebSearch;
                                        }

                                        self.cursor = 0;
                                    }

                                    edit_text
                                },
                            );

                            // separator
                            ui.separator();
                            // self.gradient_line
                            //     .draw(ui, 100.0, ui.available_width(), 1.3);
                            ui.add_space(4.);

                            match self.mode {
                                BarMode::Normal => {
                                    ui.horizontal(|ui| {
                                        ui.add_space(6.);
                                        ui.small("All apps");
                                    });
                                    self.render_app_list(ui);
                                }
                                BarMode::Calculator => {
                                    let mut f = Frame::default().show(ui, |ui| {
                                        ui.with_layout(
                                            Layout::left_to_right(egui::Align::Center),
                                            |ui| {
                                                ui.vertical(|ui| {
                                                    ui.heading(&self.search_input);
                                                    ui.small("=");
                                                    let eval_result = eval(&self.search_input)
                                                        .unwrap_or("n/a".into())
                                                        .to_string();
                                                    if ui.input_mut(|i| {
                                                        i.consume_key(Modifiers::NONE, Key::Enter)
                                                    }) {
                                                        ctx.output_mut(|w| {
                                                            w.copied_text = eval_result.clone()
                                                        });
                                                        self.visible = false;
                                                        ui.ctx().send_viewport_cmd(
                                                            egui::ViewportCommand::Visible(
                                                                self.visible,
                                                            ),
                                                        );
                                                    }
                                                    ui.heading(eval_result);
                                                });
                                            },
                                        );
                                    });
                                }
                                BarMode::WebSearch => {
                                    let mut f = Frame::default().show(ui, |ui| {
                                        ui.with_layout(
                                            Layout::left_to_right(egui::Align::Center),
                                            |ui| {
                                                ui.hyperlink(format!(
                                                    "https://www.google.com/search?q={}",
                                                    self.search_input
                                                        .split("/")
                                                        .skip(1)
                                                        .next()
                                                        .unwrap()
                                                ));
                                            },
                                        );
                                    });
                                }
                                _ => {}
                            }
                        });
                    });
            });

        TopBottomPanel::bottom("status_bar")
            .min_height(29.)
            .frame(Frame::default().fill(Color32::from_hex("#1C2541").unwrap()))
            .show(ctx, |ui: &mut Ui| {
                if let Ok(msg) = self.rx.try_recv() {
                    if self.visible {
                        ctx.send_viewport_cmd(egui::ViewportCommand::Visible(false));
                        self.visible = false;
                    } else {
                        ctx.send_viewport_cmd(egui::ViewportCommand::Visible(true));
                        self.visible = true;
                    }
                }
                // self.gradient_line
                // .draw(ui, 100.0, ui.available_width(), 2.0, Color32::RED);
                // self.gradient_line.draw_moving_gradient_line(
                //     ui,
                //     100.0,
                //     ui.available_width(),
                //     2.0,
                //     20.0,
                // );
                ui.horizontal(|ui| {
                    ui.with_layout(Layout::left_to_right(egui::Align::Center), |ui| {
                        ui.add_space(8.);
                        ui.vertical(|ui| {
                            ui.add_space(8.);
                            if ui.label(GEAR_SIX).clicked() {
                                ctx.show_viewport_immediate(
                                    ViewportId::from_hash_of("settings"),
                                    ViewportBuilder::default(),
                                    |e, u| {},
                                );
                            }
                        });
                    });
                    ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
                        ui.add_space(8.);
                        ui.vertical(|ui| {
                            ui.add_space(8.);
                            ui.label("Open applications");
                            // ui.label(GEAR_SIX);
                        });
                    });
                    // ui.with_layout(Layout::right_to_left(egui::Align::Max), |ui| {
                    //     ui.small("Open applications");
                    // });
                });
            });
    }
}
