// Fragments - status_header.rs
// Copyright (C) s2023  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, RefCell};

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

use crate::utils;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[template(resource = "/de/haeckerfelix/Fragments/gtk/status_header.ui")]
    #[properties(wrapper_type = super::FrgStatusHeader)]
    pub struct FrgStatusHeader {
        #[property(get, set = Self::set_mimetype)]
        mimetype: RefCell<String>,
        #[property(get, set)]
        title: RefCell<String>,
        #[property(get, set = Self::set_downloaded_bytes)]
        downloaded_bytes: Cell<u64>,
        #[property(get, set = Self::set_total_bytes)]
        total_bytes: Cell<u64>,
        #[property(get, set)]
        eta: RefCell<String>,

        #[template_child]
        mimetype_image: TemplateChild<gtk::Image>,
        #[template_child]
        title_label: TemplateChild<gtk::Label>,
        #[template_child]
        downloaded_label: TemplateChild<gtk::Label>,
        #[template_child]
        total_label: TemplateChild<gtk::Label>,
        #[template_child]
        eta_label: TemplateChild<gtk::Label>,
        #[template_child]
        progressbar: TemplateChild<gtk::ProgressBar>,
    }

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

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

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

    #[glib::derived_properties]
    impl ObjectImpl for FrgStatusHeader {
        fn constructed(&self) {
            self.parent_constructed();

            self.obj()
                .bind_property("title", &self.title_label.get(), "label")
                .sync_create()
                .build();
            self.obj()
                .bind_property("eta", &self.eta_label.get(), "label")
                .sync_create()
                .build();
        }
    }

    impl WidgetImpl for FrgStatusHeader {}

    impl BinImpl for FrgStatusHeader {}

    impl FrgStatusHeader {
        pub fn set_downloaded_bytes(&self, bytes: u64) {
            let downloaded = utils::format_size(bytes.try_into().unwrap());
            self.downloaded_label.set_text(&downloaded);

            self.downloaded_bytes.set(bytes);
            self.update_progressbar();
        }

        pub fn set_total_bytes(&self, bytes: u64) {
            let total = utils::format_size(bytes.try_into().unwrap());
            self.total_label.set_text(&total);

            self.total_bytes.set(bytes);
            self.update_progressbar();
        }

        pub fn set_mimetype(&self, mimetype: &str) {
            utils::set_mimetype_image(mimetype, &self.mimetype_image.get());
        }

        fn update_progressbar(&self) {
            let f = self.obj().downloaded_bytes() as f64 / self.obj().total_bytes() as f64;
            self.progressbar.set_fraction(f);
        }
    }
}

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

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

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