use adw::prelude::*;

/// Attach a numpad popover to any editable widget (gtk::Entry, adw::EntryRow, etc.).
/// The popover opens on click and provides digit entry, operators, and expression evaluation.
pub fn attach_numpad<W>(entry: &W)
where
    W: IsA<gtk::Widget> + IsA<gtk::Editable> + Clone + 'static,
{
    let numpad_popover = gtk::Popover::new();
    numpad_popover.set_parent(entry);
    numpad_popover.set_autohide(true);

    let numpad_outer = gtk::Box::new(gtk::Orientation::Vertical, 8);
    numpad_outer.set_margin_top(8);
    numpad_outer.set_margin_bottom(8);
    numpad_outer.set_margin_start(8);
    numpad_outer.set_margin_end(8);

    let numpad_grid = gtk::Grid::new();
    numpad_grid.set_row_spacing(6);
    numpad_grid.set_column_spacing(6);
    numpad_grid.add_css_class("numpad-grid");

    let keys = [
        ("7", 0, 0), ("8", 0, 1), ("9", 0, 2),
        ("4", 1, 0), ("5", 1, 1), ("6", 1, 2),
        ("1", 2, 0), ("2", 2, 1), ("3", 2, 2),
        (".", 3, 0), ("0", 3, 1),
    ];

    for (label, row, col) in &keys {
        let btn = gtk::Button::with_label(label);
        btn.set_hexpand(true);

        let entry_ref = entry.clone();
        let l = label.to_string();
        btn.connect_clicked(move |_| {
            let current = entry_ref.text().to_string();
            // Only restrict decimal within the current number segment (after last operator)
            if l == "." {
                let last_segment = current.rsplit(|c: char| "+-*/".contains(c)).next().unwrap_or("");
                if last_segment.contains('.') {
                    return;
                }
            }
            if l != "." {
                let last_segment = current.rsplit(|c: char| "+-*/".contains(c)).next().unwrap_or("");
                if let Some(dot_pos) = last_segment.find('.') {
                    if last_segment.len() - dot_pos > 2 {
                        return;
                    }
                }
            }
            entry_ref.set_text(&format!("{}{}", current, l));
            entry_ref.set_position(-1);
        });
        numpad_grid.attach(&btn, *col, *row, 1, 1);
    }

    let backspace_btn = gtk::Button::with_label("\u{232b}");
    backspace_btn.set_hexpand(true);

    backspace_btn.add_css_class("destructive-action");
    {
        let entry_ref = entry.clone();
        backspace_btn.connect_clicked(move |_| {
            let current = entry_ref.text().to_string();
            if !current.is_empty() {
                entry_ref.set_text(&current[..current.len() - 1]);
                entry_ref.set_position(-1);
            }
        });
    }
    numpad_grid.attach(&backspace_btn, 2, 3, 1, 1);

    // Operator buttons in the 4th column
    let ops = [
        ("/", 0, 3),
        ("*", 1, 3),
        ("-", 2, 3),
        ("+", 3, 3),
    ];

    for (label, row, col) in &ops {
        let btn = gtk::Button::with_label(label);
        btn.set_hexpand(true);

        btn.add_css_class("numpad-op");
        let entry_ref = entry.clone();
        let l = label.to_string();
        btn.connect_clicked(move |_| {
            let current = entry_ref.text().to_string();
            if current.is_empty() {
                return;
            }
            // Don't allow consecutive operators - replace the last one
            if let Some(last) = current.chars().last() {
                if "+-*/".contains(last) {
                    entry_ref.set_text(&format!("{}{}", &current[..current.len() - 1], l));
                    entry_ref.set_position(-1);
                    return;
                }
            }
            entry_ref.set_text(&format!("{}{}", current, l));
            entry_ref.set_position(-1);
        });
        numpad_grid.attach(&btn, *col, *row, 1, 1);
    }

    // Equals button spanning full width below the grid
    let equals_btn = gtk::Button::with_label("=");
    equals_btn.set_hexpand(true);

    equals_btn.add_css_class("suggested-action");
    {
        let entry_ref = entry.clone();
        equals_btn.connect_clicked(move |_| {
            let current = entry_ref.text().to_string();
            if let Some(result) = outlay_core::expr::eval_expr(&current) {
                // Format: strip trailing zeros but keep up to 2 decimal places
                let formatted = format!("{:.2}", result);
                let formatted = formatted.trim_end_matches('0').trim_end_matches('.');
                entry_ref.set_text(formatted);
                entry_ref.set_position(-1);
            }
        });
    }
    numpad_grid.attach(&equals_btn, 0, 4, 4, 1);

    numpad_outer.append(&numpad_grid);

    let action_box = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    action_box.set_margin_top(4);
    action_box.set_homogeneous(true);

    let cancel_btn = gtk::Button::with_label("Cancel");

    cancel_btn.add_css_class("flat");
    {
        let popover_ref = numpad_popover.clone();
        let entry_ref = entry.clone();
        cancel_btn.connect_clicked(move |_| {
            entry_ref.set_text("");
            popover_ref.popdown();
        });
    }

    let confirm_btn = gtk::Button::with_label("Done");

    confirm_btn.add_css_class("suggested-action");
    {
        let popover_ref = numpad_popover.clone();
        confirm_btn.connect_clicked(move |_| {
            popover_ref.popdown();
        });
    }

    action_box.append(&cancel_btn);
    action_box.append(&confirm_btn);
    numpad_outer.append(&action_box);

    numpad_popover.set_child(Some(&numpad_outer));

    let click_ctrl = gtk::GestureClick::new();
    click_ctrl.set_propagation_phase(gtk::PropagationPhase::Capture);
    let popover_ref = numpad_popover.clone();
    click_ctrl.connect_released(move |_, _, _, _| {
        if !popover_ref.is_visible() {
            popover_ref.popup();
        }
    });
    entry.add_controller(click_ctrl);
}
