// Fragments - connection_row.rs
// Copyright (C) 2022-2023  Felix Häcker <haeckerfelix@gnome.org>
//
// This program 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.
//
// This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.

use std::cell::{Cell, OnceCell};

use glib::{subclass, Properties};
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate};

use crate::app::FrgApplication;
use crate::backend::{secret_store, FrgConnection, FrgConnectionManager};
use crate::config;
use crate::i18n::i18n;

mod imp {
    use super::*;

    #[derive(Default, Debug, CompositeTemplate, Properties)]
    #[template(resource = "/de/haeckerfelix/Fragments/gtk/connection_row.ui")]
    #[properties(wrapper_type = super::FrgConnectionRow)]
    pub struct FrgConnectionRow {
        #[template_child]
        pub icon: TemplateChild<gtk::Image>,
        #[template_child]
        pub title: TemplateChild<gtk::Label>,
        #[template_child]
        pub subtitle: TemplateChild<gtk::Label>,
        #[template_child]
        pub checkmark: TemplateChild<gtk::Image>,
        #[template_child]
        pub remove_button: TemplateChild<gtk::Button>,

        #[property(get, set, construct_only)]
        pub connection: OnceCell<FrgConnection>,
        #[property(get, set)]
        pub selected: Cell<bool>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for FrgConnectionRow {
        const NAME: &'static str = "FrgConnectionRow";
        type ParentType = gtk::ListBoxRow;
        type Type = super::FrgConnectionRow;

        fn class_init(klass: &mut Self::Class) {
            klass.bind_template();
            klass.bind_template_callbacks();
        }

        fn instance_init(obj: &subclass::InitializingObject<Self>) {
            obj.init_template();
        }
    }

    #[glib::derived_properties]
    impl ObjectImpl for FrgConnectionRow {
        fn constructed(&self) {
            self.parent_constructed();
            let con = self.obj().connection();

            self.title.set_label(&con.title());
            self.subtitle.set_label(&con.address());

            if con.is_fragments() {
                let icon_name = if config::PROFILE == "development" {
                    "de.haeckerfelix.Fragments.Devel-symbolic"
                } else {
                    "de.haeckerfelix.Fragments-symbolic"
                };
                self.icon.set_icon_name(Some(icon_name));
                self.subtitle.set_label(&i18n("This computer"));
                self.remove_button.set_visible(false);
            } else {
                self.icon.set_icon_name(Some("network-server-symbolic"));
            }

            self.obj()
                .bind_property("selected", &self.checkmark.get(), "visible")
                .build();
        }
    }

    impl WidgetImpl for FrgConnectionRow {}

    impl ListBoxRowImpl for FrgConnectionRow {}

    #[gtk::template_callbacks]
    impl FrgConnectionRow {
        #[template_callback]
        async fn remove_button_clicked(&self) {
            // Remove stored secrets
            if let Err(e) = secret_store::remove(&self.obj().connection()).await {
                error!("Unable to remove secret: {}", e);
            }

            // Connect with default connection
            let app = FrgApplication::default();
            app.activate_action(
                "set-connection",
                Some(&FrgConnection::default().uuid().to_variant()),
            );

            let connections = FrgConnectionManager::default().connections();
            let pos = connections
                .find(&self.obj().connection())
                .expect("Unable to find connection to remove");
            connections.remove(pos);
        }
    }
}

glib::wrapper! {
    pub struct FrgConnectionRow(
        ObjectSubclass<imp::FrgConnectionRow>)
        @extends gtk::Widget, gtk::ListBoxRow;
}

impl FrgConnectionRow {
    pub fn new(connection: &FrgConnection) -> Self {
        glib::Object::builder()
            .property("connection", connection)
            .build()
    }
}
