use egui::{Button, Color32, Frame, Rect, ScrollArea, Slider, TextEdit, Vec2};
use serde::{Deserialize, Serialize};
use tgnt::{layer::Layer, layout::Layout};

fn main() {
    let native_options = eframe::NativeOptions::default();
    eframe::run_native(
        "tgnt keyboard editor",
        native_options,
        Box::new(|cc| Box::new(App::new(cc))),
    )
    .expect("Failed to run program");
}

/// We derive Deserialize/Serialize so we can persist app state on shutdown.
#[derive(Default, Deserialize, Serialize)]
#[serde(default)] // if we add new fields, give them default values when deserializing old state
pub struct App {
    layout: RonEdit<Layout>,

    layers: Vec<RonEdit<Layer>>,

    u1: f32,
    margin: f32,
}

#[derive(Deserialize, Serialize)]
struct RonEdit<T> {
    pub t: T,
    pub ron: String,
    pub error: String,
}

impl<T: Serialize> RonEdit<T> {
    pub fn new(t: T) -> Self {
        RonEdit {
            ron: ron::ser::to_string_pretty(&t, Default::default()).unwrap(),
            error: String::new(),
            t,
        }
    }
}

impl<T: Default + Serialize> Default for RonEdit<T> {
    fn default() -> Self {
        RonEdit::new(Default::default())
    }
}

impl App {
    /// Called once before the first frame.
    pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
        // This is also where you can customize the look and feel of egui using
        // `cc.egui_ctx.set_visuals` and `cc.egui_ctx.set_fonts`.

        // Load previous app state (if any).
        // Note that you must enable the `persistence` feature for this to work.
        if let Some(storage) = cc.storage {
            return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default();
        }

        let layer_str = include_str!("default_layer.ron");
        let layer: Layer = ron::from_str(&layer_str).expect("Failed to deserialize default layer");

        let layout_str = include_str!("default_layout.ron");
        let layout: Layout =
            ron::from_str(&layout_str).expect("Failed to deserialize default layout");

        Self {
            layers: vec![RonEdit::new(layer)],
            layout: RonEdit::new(layout),
            u1: 75.0,
            margin: 2.0,
        }
    }
}

impl eframe::App for App {
    /// Called by the frame work to save state before shutdown.
    fn save(&mut self, storage: &mut dyn eframe::Storage) {
        eframe::set_value(storage, eframe::APP_KEY, self);
    }

    /// Called each time the UI needs repainting, which may be many times per second.
    /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        let Self {
            margin,
            u1,
            layout,
            layers,
        } = self;

        #[cfg(not(target_arch = "wasm32"))] // no File->Quit on web pages!
        egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
            // The top panel is often a good place for a menu bar:
            egui::menu::bar(ui, |ui| {
                ui.menu_button("File", |ui| {
                    if ui.button("Quit").clicked() {
                        _frame.close();
                    }
                });
            });
        });

        egui::SidePanel::left("side_panel")
            .resizable(true)
            .width_range(250.0..=500.0)
            .show(ctx, |ui| {
                ScrollArea::vertical().show(ui, |ui| {
                    ui.heading("Side Panel");
                    ui.label("u1");
                    ui.add(Slider::new(u1, 20.0..=150.0));
                    ui.label("margin");
                    ui.add(Slider::new(margin, 0.0..=20.0));

                    ui.collapsing("Layout", |ui| {
                        if ui
                            .add(TextEdit::multiline(&mut layout.ron).code_editor())
                            .changed()
                        {
                            layout.error.clear();
                            match ron::from_str(&layout.ron) {
                                Ok(new) => layout.t = new,
                                Err(e) => layout.error = e.to_string(),
                            }
                        }

                        if !layout.error.is_empty() {
                            ui.add(
                                TextEdit::multiline(&mut layout.error)
                                    .interactive(false)
                                    .text_color(Color32::RED),
                            );
                        }
                    });

                    let mut to_delete = None;
                    for (i, layer) in layers.iter_mut().enumerate() {
                        ui.collapsing(format!("Layer {i}"), |ui| {
                            if ui.button("Delete").clicked() {
                                to_delete = Some(i);
                            }

                            if ui
                                .add(TextEdit::multiline(&mut layer.ron).code_editor())
                                .changed()
                            {
                                layer.error.clear();
                                match ron::from_str(&layer.ron) {
                                    Ok(new) => layer.t = new,
                                    Err(e) => layer.error = e.to_string(),
                                }
                            }

                            if !layer.error.is_empty() {
                                ui.add(
                                    TextEdit::multiline(&mut layer.error)
                                        .interactive(false)
                                        .text_color(Color32::RED),
                                );
                            }
                        });
                    }

                    if let Some(i) = to_delete {
                        layers.remove(i);
                    }

                    if ui.button("Add layer").clicked() {
                        layers.push(RonEdit::default());
                    }
                });
            });

        egui::CentralPanel::default().show(ctx, |ui| {
            ScrollArea::both().show(ui, |ui| {
                for layer in layers {
                    Frame::none().show(ui, |ui| {
                        for (i, button) in layer.t.buttons.iter().enumerate() {
                            if let Some(geometry) = layout.t.buttons.get(i) {
                                let size = Vec2::new(
                                    *u1 * geometry.w - *margin * 2.0,
                                    *u1 * geometry.h - *margin * 2.0,
                                );
                                let offset = Vec2::new(
                                    *u1 * geometry.x + *margin,
                                    *u1 * geometry.y + *margin,
                                );
                                let rect = Rect::from_min_size(ui.min_rect().min + offset, size);
                                ui.put(rect, Button::new(button.to_string()));
                            }
                        }
                    });
                    ui.separator();
                }
            })
        });
    }
}
