/*
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>

This file is part of On the Grid.

On the Grid is free software: you can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

On the Grid is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
*/

use std::{cell::RefCell, rc::Rc};

use adw::prelude::*;
use glib::Object;
use gtk::{subclass::prelude::*};
use otg_core::{Config, ConfigOption, LibraryPath};

fn library_chooser_row(
    parent: &impl IsA<gtk::Window>,
    library_path: Option<LibraryPath>,
    on_library_chosen: Rc<impl Fn(ConfigOption) + 'static>,
) -> adw::ActionRow {
    let dialog = gtk::FileDialog::builder().build();

    let dialog_button = gtk::Button::builder()
        .child(&gtk::Label::new(Some("Select Library")))
        .valign(gtk::Align::Center)
        .build();

    let _parent = parent.clone();

    let library_row = adw::ActionRow::builder()
        .title("Library Path")
        .subtitle(
            library_path
                .map(|LibraryPath(path)| path.to_string_lossy().into_owned())
                .unwrap_or("No library set".to_owned()),
        )
        .css_classes(["preference-item"])
        .build();

    dialog_button.connect_clicked({
        let library_row = library_row.clone();
        move |_| {
            let no_parent: Option<&gtk::Window> = None;
            let not_cancellable: Option<&gio::Cancellable> = None;
            let on_library_chosen = on_library_chosen.clone();
            dialog.select_folder(no_parent, not_cancellable, {
                let library_row = library_row.clone();
                move |result| match result {
                    Ok(path) => {
                        let path_str: String =
                            path.path().unwrap().into_os_string().into_string().unwrap();
                        library_row.set_subtitle(&path_str);
                        on_library_chosen(ConfigOption::LibraryPath(LibraryPath(
                            path.path().unwrap(),
                        )))
                    }
                    Err(err) => println!("Error choosing a library: {:?}", err),
                }
            });
        }
    });

    library_row.add_suffix(&dialog_button);

    library_row
}

pub struct SettingsPrivate {}

#[glib::object_subclass]
impl ObjectSubclass for SettingsPrivate {
    const NAME: &'static str = "Settings";
    type Type = SettingsView;
    type ParentType = gtk::Frame;

    fn new() -> Self {
        Self {}
    }
}

impl ObjectImpl for SettingsPrivate {}
impl WidgetImpl for SettingsPrivate {}
#[allow(deprecated)]
impl FrameImpl for SettingsPrivate {}

glib::wrapper! {
    pub struct SettingsView(ObjectSubclass<SettingsPrivate>) @extends gtk::Frame, gtk::Widget, @implements gtk::Accessible, gtk::Orientable;
}

impl SettingsView {
    pub fn new(
        parent: &impl IsA<gtk::Window>,
        config: Config,
        on_save: impl Fn(Config) + 'static,
        on_cancel: impl Fn() + 'static,
    ) -> Self {
        let s: Self = Object::builder().build();
        let config = Rc::new(RefCell::new(config));

        let group = adw::PreferencesGroup::builder().build();

        let library_row = library_chooser_row(
            parent,
            config.borrow().get(),
            Rc::new({
                let config = config.clone();
                move |library_path| {
                    config.borrow_mut().set(library_path);
                }
            }),
        );
        group.add(&library_row);

        let cancel_button = gtk::Button::builder().label("Cancel").build();
        cancel_button.connect_clicked(move |_| on_cancel());
        let save_button = gtk::Button::builder().label("Save").build();
        save_button.connect_clicked({
            let config = config.clone();
            move |_| on_save(config.borrow().clone())
        });

        let action_row = gtk::Box::builder()
            .orientation(gtk::Orientation::Horizontal)
            .halign(gtk::Align::End)
            .valign(gtk::Align::End)
            .build();
        action_row.append(&cancel_button);
        action_row.append(&save_button);

        let preferences_box = gtk::Box::builder()
            .orientation(gtk::Orientation::Vertical)
            .build();
        preferences_box.append(&group);

        let layout = gtk::Box::builder()
            .orientation(gtk::Orientation::Vertical)
            .spacing(8)
            .build();
        layout.append(&preferences_box);
        layout.append(&action_row);

        s.set_child(Some(&layout));
        s.set_css_classes(&["settings-view"]);

        s
    }
}
