//! Reusable editor widgets: icon buttons, tool toggles, menu labels.

use std::hash::Hash;

use bevy_egui::egui::{self, Button, FontId, RichText, Ui, WidgetText};
use egui_phosphor_icons::Icon;

use super::theme::{
    ACCENT, ACCENT_HOVER, BORDER, ELEVATED_BG, SELECTION, SELECTION_BG, SUCCESS, TEXT_MUTED,
    TEXT_SELECTED, WIDGET_BG,
};

const PHOSPHOR: &str = "phosphor-regular";

pub fn phosphor_icon(icon: Icon, size: f32) -> RichText {
    phosphor_icon_text(icon.as_str(), size)
}

pub fn phosphor_icon_text(icon: &str, size: f32) -> RichText {
    RichText::new(icon).font(FontId::new(size, egui::FontFamily::Name(PHOSPHOR.into())))
}

/// Large transport control (Play / Pause / Stop / Eject), icon-only with a tooltip.
pub fn transport_button_large(
    ui: &mut Ui,
    id_salt: impl Hash,
    icon: Icon,
    tooltip: &str,
    accent: bool,
) -> egui::Response {
    const SIZE: f32 = 40.0;
    const ICON_PX: f32 = 20.0;

    let fill = if accent {
        SUCCESS
    } else {
        ELEVATED_BG.linear_multiply(0.9)
    };
    let (_, rect) = ui.allocate_space(egui::vec2(SIZE, SIZE));
    let response = ui.interact(rect, ui.make_persistent_id(id_salt), egui::Sense::click());
    response.widget_info(|| {
        egui::WidgetInfo::labeled(egui::WidgetType::Button, ui.is_enabled(), tooltip)
    });
    let fill = if response.is_pointer_button_down_on() {
        fill.linear_multiply(0.82)
    } else if response.hovered() {
        fill.linear_multiply(1.15)
    } else {
        fill
    };
    let stroke = egui::Stroke::new(
        if response.hovered() { 1.5 } else { 1.0 },
        if accent {
            SUCCESS.linear_multiply(1.15)
        } else if response.hovered() {
            TEXT_MUTED
        } else {
            BORDER
        },
    );
    ui.painter()
        .rect(rect, 6.0, fill, stroke, egui::StrokeKind::Inside);
    ui.painter().text(
        rect.center(),
        egui::Align2::CENTER_CENTER,
        icon.as_str(),
        FontId::new(ICON_PX, egui::FontFamily::Name(PHOSPHOR.into())),
        TEXT_SELECTED,
    );
    response.on_hover_text(tooltip)
}

pub fn icon_button(ui: &mut Ui, icon: Icon, tooltip: &str) -> egui::Response {
    ui.add(
        Button::new(phosphor_icon(icon, 17.0))
            .fill(WIDGET_BG.linear_multiply(0.78))
            .stroke(egui::Stroke::new(1.0, BORDER))
            .min_size(egui::vec2(32.0, 32.0)),
    )
    .on_hover_text(tooltip)
}

pub fn icon_button_small(ui: &mut Ui, icon: Icon, tooltip: &str) -> egui::Response {
    ui.add(
        Button::new(phosphor_icon(icon, 16.0))
            .fill(WIDGET_BG.linear_multiply(0.72))
            .stroke(egui::Stroke::new(1.0, BORDER))
            .min_size(egui::vec2(27.0, 27.0))
            .corner_radius(4.0),
    )
    .on_hover_text(tooltip)
}

pub fn tool_button(ui: &mut Ui, icon: Icon, selected: bool, tooltip: &str) -> egui::Response {
    tool_button_with_color(ui, icon, selected, tooltip, SELECTION_BG, SELECTION)
}

pub fn tool_button_accent(
    ui: &mut Ui,
    icon: Icon,
    selected: bool,
    tooltip: &str,
) -> egui::Response {
    tool_button_with_color(
        ui,
        icon,
        selected,
        tooltip,
        ACCENT.linear_multiply(0.84),
        ACCENT_HOVER,
    )
}

fn tool_button_with_color(
    ui: &mut Ui,
    icon: Icon,
    selected: bool,
    tooltip: &str,
    selected_fill: egui::Color32,
    selected_stroke: egui::Color32,
) -> egui::Response {
    let fill = if selected {
        selected_fill
    } else {
        WIDGET_BG.linear_multiply(0.82)
    };
    ui.add(
        Button::new(phosphor_icon(icon, 17.0))
            .fill(fill)
            .stroke(egui::Stroke::new(
                1.0,
                if selected { selected_stroke } else { BORDER },
            ))
            .min_size(egui::vec2(30.0, 30.0))
            .corner_radius(4.0),
    )
    .on_hover_text(tooltip)
}

pub fn menu_item(
    ui: &mut Ui,
    label: &str,
    shortcut: Option<&str>,
    enabled: bool,
) -> egui::Response {
    let text: WidgetText = if let Some(key) = shortcut {
        RichText::new(format!("{label}\t{key}")).into()
    } else {
        label.into()
    };
    ui.add_enabled(enabled, egui::Button::new(text))
}

pub fn toolbar_separator(ui: &mut Ui) {
    ui.add_space(4.0);
    ui.separator();
    ui.add_space(4.0);
}

pub fn panel_toolbar_row<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> R {
    ui.horizontal(|ui| {
        ui.spacing_mut().item_spacing.x = 4.0;
        add_contents(ui)
    })
    .inner
}
