//! Self-contained "are you sure?" modal.
//!
//! Holds (title, message, action) where `action` is the App's
//! [`ConfirmAction`] enum — the dialog never knows what the action
//! does, just hands it back when the user clicks Confirm. Avoids
//! the `Box<dyn FnOnce(&mut App)>` callback pattern that couples
//! the dialog file to the App's full method surface.

use eframe::egui;

/// What the user just confirmed (or cancelled). The App matches and
/// dispatches the corresponding worker command.
pub enum ConfirmAction {
    /// User permanently deletes a stored secret.
    RevokeSecret { name: String },
    /// User removes all access rules for a binary.
    RevokePolicyBinary { binary: String },
}

impl ConfirmAction {
    /// Default title for this action — what users see at the top of
    /// the dialog. Centralizes UX copy so the App doesn't have to
    /// re-state it at every call site.
    pub fn title(&self) -> &'static str {
        match self {
            Self::RevokeSecret { .. } => "Revoke Secret",
            Self::RevokePolicyBinary { .. } => "Revoke Binary Access",
        }
    }

    /// Default message body for this action.
    pub fn message(&self) -> String {
        match self {
            Self::RevokeSecret { name } => {
                format!("Permanently delete secret '{name}'? This cannot be undone.")
            }
            Self::RevokePolicyBinary { binary } => {
                format!("Remove all access rules for '{binary}'?")
            }
        }
    }
}

/// In-flight confirmation dialog state. App holds `Option<ConfirmDialog>`
/// and renders only when `Some`.
pub struct ConfirmDialog {
    /// What the user is being asked to confirm. Same value handed
    /// back via [`Outcome::Confirmed`] on click.
    pub action: ConfirmAction,
}

impl ConfirmDialog {
    pub fn new(action: ConfirmAction) -> Self {
        Self { action }
    }
}

/// Render outcome for one frame.
pub enum Outcome {
    /// User clicked Confirm — App should dispatch the action and drop
    /// the dialog.
    Confirmed(ConfirmAction),
    /// User clicked Cancel — App should drop the dialog without acting.
    Cancelled,
    /// No state change this frame.
    None,
}

/// Render the dialog. Takes `Option<ConfirmDialog>` so the App can
/// pass `&mut self.confirm` directly; we drop the contained value on
/// any decision so the App doesn't have to remember to clear it.
pub fn render(ctx: &egui::Context, slot: &mut Option<ConfirmDialog>) -> Outcome {
    if slot.is_none() {
        return Outcome::None;
    }

    let screen = ctx.viewport_rect();
    egui::Area::new(egui::Id::new("confirm_dim"))
        .anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
        .show(ctx, |ui| {
            ui.painter()
                .rect_filled(screen, 0.0, egui::Color32::from_black_alpha(160));
        });

    let mut decision: Option<bool> = None;

    egui::Area::new(egui::Id::new("confirm_dialog"))
        .anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
        .show(ctx, |ui| {
            egui::Frame::new()
                .fill(ui.visuals().window_fill())
                .stroke(ui.visuals().window_stroke())
                .corner_radius(12.0)
                .inner_margin(24.0)
                .show(ui, |ui| {
                    ui.set_min_width(380.0);
                    if let Some(dialog) = slot.as_ref() {
                        ui.heading(dialog.action.title());
                        ui.add_space(8.0);
                        ui.label(dialog.action.message());
                        ui.add_space(16.0);
                        ui.horizontal(|ui| {
                            if ui.button("Cancel").clicked() {
                                decision = Some(false);
                            }
                            ui.add_space(8.0);
                            if ui
                                .add(
                                    egui::Button::new("Confirm")
                                        .fill(egui::Color32::from_rgb(220, 38, 38))
                                        .min_size(egui::vec2(110.0, 28.0))
                                        .corner_radius(6.0),
                                )
                                .clicked()
                            {
                                decision = Some(true);
                            }
                        });
                    }
                });
        });

    match decision {
        Some(true) => slot
            .take()
            .map_or(Outcome::None, |d| Outcome::Confirmed(d.action)),
        Some(false) => {
            *slot = None;
            Outcome::Cancelled
        }
        None => Outcome::None,
    }
}
