// Fragments - stats_dialog.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 adw::prelude::*;
use adw::subclass::prelude::*;
use glib::{clone, subclass, BindingFlags};
use gtk::{glib, CompositeTemplate};

use crate::backend::FrgConnectionManager;
use crate::i18n::{i18n_f, ni18n_f};
use crate::utils;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate)]
    #[template(resource = "/de/haeckerfelix/Fragments/gtk/stats_dialog.ui")]
    pub struct FrgStatsDialog {
        #[template_child]
        remote_notice_group: TemplateChild<adw::PreferencesGroup>,
        #[template_child]
        remote_notice_row: TemplateChild<adw::ActionRow>,

        #[template_child]
        version_label: TemplateChild<gtk::Label>,

        #[template_child]
        download_speed_label: TemplateChild<gtk::Label>,
        #[template_child]
        upload_speed_label: TemplateChild<gtk::Label>,

        #[template_child]
        torrents_label: TemplateChild<gtk::Label>,
        #[template_child]
        active_torrents_label: TemplateChild<gtk::Label>,
        #[template_child]
        paused_torrents_label: TemplateChild<gtk::Label>,
        #[template_child]
        downloaded_torrents_label: TemplateChild<gtk::Label>,

        #[template_child]
        current_time_active_label: TemplateChild<gtk::Label>,
        #[template_child]
        current_downloaded_label: TemplateChild<gtk::Label>,
        #[template_child]
        current_uploaded_label: TemplateChild<gtk::Label>,
        #[template_child]
        current_files_added_label: TemplateChild<gtk::Label>,

        #[template_child]
        cumulative_time_active_label: TemplateChild<gtk::Label>,
        #[template_child]
        cumulative_downloaded_label: TemplateChild<gtk::Label>,
        #[template_child]
        cumulative_uploaded_label: TemplateChild<gtk::Label>,
        #[template_child]
        cumulative_files_added_label: TemplateChild<gtk::Label>,
        #[template_child]
        cumulative_sessions_label: TemplateChild<gtk::Label>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for FrgStatsDialog {
        const NAME: &'static str = "FrgStatsDialog";
        type ParentType = adw::Dialog;
        type Type = super::FrgStatsDialog;

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

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

    impl ObjectImpl for FrgStatsDialog {
        fn constructed(&self) {
            self.parent_constructed();

            FrgConnectionManager::default().connect_current_connection_notify(
                clone!(@weak self as this => move |_|{
                    this.update_remote_notice();
                }),
            );

            self.bind_properties();
            self.update_format_strings();
            self.update_remote_notice();
        }
    }

    impl WidgetImpl for FrgStatsDialog {}

    impl AdwDialogImpl for FrgStatsDialog {}

    impl FrgStatsDialog {
        fn bind_properties(&self) {
            let client = FrgConnectionManager::default().client();
            let session = client.session();
            let stats = client.session_stats();
            let current = stats.current_stats();
            let cumulative = stats.cumulative_stats();

            session
                .bind_property("version", &self.version_label.get(), "label")
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            stats
                .bind_property("torrent-count", &self.torrents_label.get(), "label")
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            stats
                .bind_property(
                    "active-torrent-count",
                    &self.active_torrents_label.get(),
                    "label",
                )
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            stats
                .bind_property(
                    "paused-torrent-count",
                    &self.paused_torrents_label.get(),
                    "label",
                )
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            stats
                .bind_property(
                    "downloaded-torrent-count",
                    &self.downloaded_torrents_label.get(),
                    "label",
                )
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            stats
                .bind_property(
                    "downloaded-torrent-count",
                    &self.downloaded_torrents_label.get(),
                    "label",
                )
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            current
                .bind_property(
                    "files-added",
                    &self.current_files_added_label.get(),
                    "label",
                )
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            cumulative
                .bind_property(
                    "files-added",
                    &self.cumulative_files_added_label.get(),
                    "label",
                )
                .flags(BindingFlags::SYNC_CREATE)
                .build();

            stats.connect_download_speed_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            stats.connect_upload_speed_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            current.connect_seconds_active_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            current.connect_downloaded_bytes_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            current.connect_uploaded_bytes_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            cumulative.connect_seconds_active_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            cumulative.connect_downloaded_bytes_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            cumulative.connect_uploaded_bytes_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));

            cumulative.connect_session_count_notify(clone!(@weak self as this => move |_|{
                this.update_format_strings();
            }));
        }

        fn update_format_strings(&self) {
            let stats = FrgConnectionManager::default().client().session_stats();
            let current = stats.current_stats();
            let cumulative = stats.cumulative_stats();

            let speed = utils::format_speed(stats.download_speed());
            self.download_speed_label.set_label(&speed);

            let speed = utils::format_speed(stats.upload_speed());
            self.upload_speed_label.set_label(&speed);

            // Current
            let time = utils::format_time(current.seconds_active().try_into().unwrap(), false);
            self.current_time_active_label.set_label(&time);

            let size = utils::format_size(current.downloaded_bytes());
            self.current_downloaded_label.set_label(&size);

            let size = utils::format_size(current.uploaded_bytes());
            self.current_uploaded_label.set_label(&size);

            // Cumulative
            let time = utils::format_time(cumulative.seconds_active().try_into().unwrap(), false);
            self.cumulative_time_active_label.set_label(&time);

            let size = utils::format_size(cumulative.downloaded_bytes());
            self.cumulative_downloaded_label.set_label(&size);

            let size = utils::format_size(cumulative.uploaded_bytes());
            self.cumulative_uploaded_label.set_label(&size);

            let started = cumulative.session_count();
            let text = ni18n_f(
                "{} time",
                "{} times",
                started.try_into().unwrap_or(2),
                &[&started.to_string()],
            );
            self.cumulative_sessions_label.set_label(&text);
        }

        fn update_remote_notice(&self) {
            let cm = FrgConnectionManager::default();

            let is_fragments = cm.current_connection().is_fragments();
            let title = cm.current_connection().title();

            self.remote_notice_group.set_visible(!is_fragments);
            self.remote_notice_row
                .set_title(&i18n_f("You are connected with “{}”", &[&title]));
        }
    }
}

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

impl FrgStatsDialog {
    pub fn new() -> Self {
        glib::Object::new()
    }
}

impl Default for FrgStatsDialog {
    fn default() -> Self {
        Self::new()
    }
}
