use egui::{Color32, Context, RichText, Theme, Ui, Visuals, style::ScrollAnimation};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
#[serde(default)]
pub struct Preferences {
    /// Enable animations
    pub animations: bool,

    /// Enable high-contrast theme
    pub high_contrast: bool,

    /// Hide the cursor when handwriting
    pub hide_handwriting_cursor: bool,

    #[serde(skip)]
    has_applied_prefs: bool,
}

impl Default for Preferences {
    fn default() -> Self {
        Self {
            animations: true,
            high_contrast: false,
            has_applied_prefs: false,
            hide_handwriting_cursor: false,
        }
    }
}

impl Preferences {
    /// Apply preferences, if they haven't already been applied.
    pub fn apply(&mut self, ctx: &Context) {
        if !self.has_applied_prefs {
            self.has_applied_prefs = true;

            let scroll_animation = if self.animations {
                ScrollAnimation::default()
            } else {
                ScrollAnimation::none()
            };

            for theme in [Theme::Dark, Theme::Light] {
                ctx.style_mut_of(theme, |style| {
                    style.scroll_animation = scroll_animation;
                });
            }

            let mut dark_visuals = Visuals::dark();
            let mut light_visuals = Visuals::light();

            dark_visuals.window_fill = Color32::from_rgb(0x1e, 0x1e, 0x1e);
            dark_visuals.panel_fill = Color32::from_rgb(0x26, 0x26, 0x26);

            light_visuals.window_fill = Color32::WHITE;
            light_visuals.panel_fill = Color32::from_rgb(0xf6, 0xf6, 0xf6);

            dark_visuals.code_bg_color = Color32::BLACK;
            light_visuals.code_bg_color = Color32::WHITE;

            if self.high_contrast {
                // widgets.active:         color of headers in textedit
                // widgets.inactive:       color of button labels
                // widgets.hovered:        color of hovered button labels
                // widgets.noninteractive: color of labels and normal textedit text

                dark_visuals.widgets.noninteractive.fg_stroke.color = Color32::WHITE;
                dark_visuals.widgets.inactive.fg_stroke.color = Color32::WHITE;
                dark_visuals.widgets.hovered.fg_stroke.color = Color32::WHITE;

                light_visuals.widgets.noninteractive.fg_stroke.color = Color32::BLACK;
                light_visuals.widgets.inactive.fg_stroke.color = Color32::BLACK;
                light_visuals.widgets.hovered.fg_stroke.color = Color32::BLACK;
            } else {
                dark_visuals.widgets.noninteractive.fg_stroke.color =
                    Color32::from_rgb(0xaa, 0xaa, 0xaa);

                light_visuals.widgets.noninteractive.fg_stroke.color =
                    Color32::from_rgb(0x11, 0x11, 0x11);
            }

            ctx.set_visuals_of(Theme::Dark, dark_visuals);
            ctx.set_visuals_of(Theme::Light, light_visuals);
        }
    }

    /// Show preference switches
    pub fn show(&mut self, ui: &mut Ui) {
        ui.label(RichText::new("Prefs").weak());

        let animations_toggle = ui.toggle_value(&mut self.animations, "Animations");
        if animations_toggle.clicked() {
            self.has_applied_prefs = false;
            self.apply(ui.ctx());
        }

        let high_contrast_toggle = ui.toggle_value(&mut self.high_contrast, "High Contrast");
        if high_contrast_toggle.clicked() {
            self.has_applied_prefs = false;
            self.apply(ui.ctx());
        }

        ui.toggle_value(&mut self.hide_handwriting_cursor, "Hide Handwriting Cursor");

        egui::widgets::global_theme_preference_buttons(ui);
    }
}
