#![windows_subsystem = "windows"]
use bevy::{prelude::*, utils::Duration, winit::WinitSettings};
use bevy_egui::{
    egui::{self, Color32},
    EguiContexts, EguiPlugin,
};

#[cfg(windows)]
const LINE_ENDING: &str = "\r\n";
#[cfg(not(windows))]
const LINE_ENDING: &str = "\n";

#[derive(Resource, Debug)]
struct InputText {
    value: String,
}

#[derive(Resource, Debug)]
struct NeedsSort {
    value: bool,
}

#[derive(Resource, Debug)]
struct NeedsStrip {
    value: bool,
}

#[derive(Resource, Debug)]
struct UITimer(Timer);

#[derive(Resource, Debug)]
struct Msg {
    value: String,
}

fn main() {
    App::new()
        .insert_resource(WinitSettings {
            focused_mode: bevy::winit::UpdateMode::Continuous,
            unfocused_mode: bevy::winit::UpdateMode::reactive_low_power(Duration::from_millis(10)),
        })
        .insert_resource(InputText {
            value: "".to_string(),
        })
        .insert_resource(Msg {
            value: "".to_string(),
        })
        .insert_resource(NeedsSort { value: false })
        .insert_resource(NeedsStrip { value: false })
        .insert_resource(UITimer(Timer::from_seconds(3., TimerMode::Once)))
        .add_plugins(DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "dsort".to_string(),
                ..Default::default()
            }),
            ..Default::default()
        }))
        .add_plugins(EguiPlugin)
        .add_systems(Startup, ui_startup)
        .add_systems(Update, ui_system)
        .add_systems(Update, process_text)
        .run();
}

fn process_text(
    mut needs_sort: ResMut<NeedsSort>,
    mut needs_strip: ResMut<NeedsStrip>,
    mut input_text: ResMut<InputText>,
) {
    let needs_processing = needs_sort.value || needs_strip.value;

    if needs_processing {
        let mut arr = input_text.value.lines().collect::<Vec<_>>();

        if needs_strip.value {
            arr.retain(|&x| !x.trim().is_empty());
            needs_strip.value = false;
        }

        if needs_sort.value {
            arr.sort_by(|&a, &b| vsort::compare(a, b));
            needs_sort.value = false;
        }

        input_text.value = arr.join(LINE_ENDING);
    }
}

fn button(label: &str) -> egui::Button {
    egui::Button::new(label).sense(egui::Sense::click_and_drag())
}

fn button_clicked(button: egui::Response) -> bool {
    button.clicked() || button.drag_stopped()
}

fn ui_startup(mut contexts: EguiContexts, mut timer: ResMut<UITimer>) {
    contexts.ctx_mut().set_visuals(egui::Visuals::light());
    let duration = timer.0.duration();
    timer.0.set_elapsed(duration);
}

fn ui_system(
    mut contexts: EguiContexts,
    mut input_text: ResMut<InputText>,
    mut needs_sort: ResMut<NeedsSort>,
    mut needs_strip: ResMut<NeedsStrip>,
    time: Res<Time>,
    mut timer: ResMut<UITimer>,
    mut msg: ResMut<Msg>,
) {
    timer.0.tick(time.delta());

    if timer.0.finished() {
        msg.value = "".to_string();
    }

    egui::CentralPanel::default().show(contexts.ctx_mut(), |ui| {
        ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
            ui.with_layout(egui::Layout::left_to_right(egui::Align::LEFT), |ui| {
                let sort_button = ui.add(button("sort"));
                if button_clicked(sort_button) {
                    needs_sort.value = true;
                    msg.value = "sorted!".to_string();
                    timer.0.reset();
                }

                let strip_button = ui.add(button("remove blanks"));
                if button_clicked(strip_button) {
                    needs_strip.value = true;
                    msg.value = "blanks removed!".to_string();
                    timer.0.reset();
                }

                let copy_button = ui.add(button("copy"));
                if button_clicked(copy_button) {
                    ui.output_mut(|o| o.copied_text = input_text.value.clone());
                    msg.value = "copied!".to_string();
                    timer.0.reset();
                }

                let clear_button = ui.add(button("clear"));
                if button_clicked(clear_button) {
                    input_text.value = "".to_string();
                    msg.value = "cleared!".to_string();
                    timer.0.reset();
                }
                ui.with_layout(
                    egui::Layout::default().with_cross_align(egui::Align::RIGHT),
                    |ui| {
                        ui.label(
                            egui::RichText::new(&msg.value)
                                .background_color(Color32::from_gray(200)),
                        )
                    },
                );
            });

            ui.add_space(5.);

            egui::ScrollArea::vertical().show(ui, |ui| {
                ui.add_sized(
                    ui.available_size(),
                    egui::TextEdit::multiline(&mut input_text.value),
                );
            });
        });
    });
}
