use crate::app::PatchpalApplication;
use gtk::glib;
use gtk::prelude::*;

pub(crate) fn create(app: &PatchpalApplication) -> gtk::Window {
    let left = shortcut_groups(&[
        ("General", &[
            ("?", "Keyboard shortcuts"),
            ("Ctrl+Q", "Quit"),
            ("c", "Show/modify the commit list"),
        ]),
        ("Hunk", &[
            ("a", "Accept the hunk"),
            ("u", "Use AI for the hunk"),
            ("n", "Next AI suggestion"),
            ("p", "Previous AI suggestion"),
            ("r", "Retry failed AI"),
            ("e", "Edit the hunk"),
            ("Del", "Remove (unapply) the hunk"),
            ("Ctrl+Z", "Undo"),
        ]),
        ("Moving around", &[
            ("Enter", "Expand/collapse the context"),
            ("Enter", "Open suggested commits window"),
            ("]", "Next file"),
            ("[", "Previous file"),
            (".", "Next unaccepted hunk"),
            (",", "Previous unaccepted hunk"),
        ]),
    ]);
    let right = shortcut_groups(&[
        ("Commands", &[
            ("Ctrl+A", "Accept all clean hunks"),
            ("Ctrl+Shift+A", "Auto accept all clean hunks"),
            ("Ctrl+]", "Next commit"),
            ("Ctrl+[", "Previous commit"),
            ("Ctrl+Enter", "Commit and quit"),
            ("Ctrl+F", "Fast forward"),
            ("Ctrl+Shift+Enter", "Fast forward and commit"),
        ]),
        ("Commit list window", &[
            ("Ctrl+W", "Close"),
            ("Ctrl+C", "Copy commit ID"),
            ("Ctrl+\u{2191}", "Move commit up"),
            ("Ctrl+\u{2193}", "Move commit down"),
            ("a", "Add commit"),
            ("Del", "Remove commit"),
            ("Ctrl+S", "Sort commits"),
            ("Ctrl+Enter", "Apply"),
        ]),
    ]);

    let sep = gtk::Separator::new(
        gtk::Orientation::Vertical,
    );
    let hbox = gtk::Box::builder()
        .orientation(gtk::Orientation::Horizontal)
        .spacing(20)
        .margin_top(10)
        .margin_bottom(18)
        .margin_start(15)
        .margin_end(15)
        .build();
    hbox.append(&left);
    hbox.append(&sep);
    hbox.append(&right);

    let window = gtk::Window::builder()
        .application(app)
        .title("Patchpal Shortcuts")
        .resizable(false)
        .child(&hbox)
        .build();

    window.connect_close_request(|w| {
        w.set_visible(false);
        glib::Propagation::Stop
    });

    let keyctrl = gtk::EventControllerKey::new();
    keyctrl.connect_key_pressed(glib::clone!(
        #[weak] window,
        #[upgrade_or] glib::Propagation::Proceed,
        move |_, keyval, _, _| {
            if keyval == gtk::gdk::Key::Escape {
                window.set_visible(false);
                glib::Propagation::Stop
            } else {
                glib::Propagation::Proceed
            }
        }
    ));
    window.add_controller(keyctrl);
    window
}

fn shortcut_groups(
    groups: &[(&str, &[(&str, &str)])],
) -> gtk::Grid {
    let grid = gtk::Grid::builder()
        .column_spacing(10)
        .row_spacing(4)
        .build();
    let mut row = 0;
    for (title, shortcuts) in groups.iter() {
        let title = gtk::Label::builder()
            .label(*title)
            .css_classes(["kbd-group-title"])
            .halign(gtk::Align::Start)
            .build();
        grid.attach(&title, 0, row, 2, 1);
        row += 1;
        for (key, desc) in shortcuts.iter() {
            let keys = key_widget(key);
            keys.set_halign(gtk::Align::End);
            let desc_label = gtk::Label::builder()
                .label(*desc)
                .halign(gtk::Align::Start)
                .build();
            grid.attach(&keys, 0, row, 1, 1);
            grid.attach(&desc_label, 1, row, 1, 1);
            row += 1;
        }
    }
    grid
}

fn key_widget(key: &str) -> gtk::Box {
    let hbox = gtk::Box::builder()
        .orientation(gtk::Orientation::Horizontal)
        .spacing(2)
        .build();
    for (i, part) in key.split('+').enumerate() {
        if i > 0 {
            hbox.append(&gtk::Label::new(Some("+")));
        }
        let key_box = gtk::Box::builder()
            .css_classes(["kbd-key"])
            .build();
        key_box.append(&gtk::Label::new(Some(part)));
        hbox.append(&key_box);
    }
    hbox
}
