use crate::i18n::gettext;
use crate::models::Container;
use crate::widgets::DistroShelfWindow;

use adw::prelude::*;
use adw::subclass::prelude::*;
use gtk::glib::clone;
use gtk::{self, gdk, glib, pango};
use std::cell::{OnceCell, RefCell};
use std::rc::Rc;

mod imp {
    use super::*;
    use gtk::glib::{Properties, derived_properties};

    // Object holding the state
    #[derive(Default, Properties)]
    #[properties(wrapper_type=super::ContainerOverview)]
    pub struct ContainerOverview {
        #[property(get, set, construct)]
        pub container: OnceCell<Container>,
        /// Handlers bound to the container's notify signals. A `SignalGroup`
        /// owns them and auto-disconnects when this widget is finalized, so
        /// they don't pile up on the (long-lived) container across overview
        /// recreations.
        pub signals: OnceCell<glib::SignalGroup>,
    }

    // The central trait for subclassing a GObject
    #[glib::object_subclass]
    impl ObjectSubclass for ContainerOverview {
        const NAME: &'static str = "ContainerOverview";
        type Type = super::ContainerOverview;
        type ParentType = adw::Bin;
    }

    #[derived_properties]
    impl ObjectImpl for ContainerOverview {
        fn constructed(&self) {
            self.parent_constructed();
        }
    }

    impl WidgetImpl for ContainerOverview {}
    impl BinImpl for ContainerOverview {}
}

glib::wrapper! {
    pub struct ContainerOverview(ObjectSubclass<imp::ContainerOverview>)
        @extends adw::Bin, gtk::Widget,
        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
}

impl ContainerOverview {
    pub fn new(container: &Container) -> Self {
        let obj: Self = glib::Object::builder()
            .property("container", container)
            .build();
        obj.set_child(Some(&obj.build_main_content(container)));
        obj
    }

    pub fn build_main_content(&self, container: &Container) -> gtk::Widget {
        let clamp = adw::Clamp::new();

        // Main container with scrolling
        let scrolled_window = gtk::ScrolledWindow::new();
        scrolled_window.set_policy(gtk::PolicyType::Never, gtk::PolicyType::Automatic);
        scrolled_window.set_vexpand(true);

        let main_box = gtk::Box::new(gtk::Orientation::Vertical, 24);
        main_box.set_margin_start(12);
        main_box.set_margin_end(12);
        main_box.set_margin_top(12);
        main_box.set_margin_bottom(24);

        // Status Group
        let status_group = adw::PreferencesGroup::new();
        status_group.set_title(&gettext("Container Status"));

        let status_row = adw::ActionRow::new();
        status_group.add_css_class("property");
        status_row.set_title(&gettext("Status"));

        let status_child = gtk::Box::new(gtk::Orientation::Horizontal, 6);
        status_child.set_valign(gtk::Align::Center);

        let stop_btn = gtk::Button::from_icon_name("media-playback-stop-symbolic");
        stop_btn.set_tooltip_text(Some(&gettext("Stop")));
        stop_btn.set_action_name(Some("win.stop-container"));
        status_child.append(&stop_btn);

        let terminal_btn = gtk::Button::from_icon_name("terminal-symbolic");
        terminal_btn.set_tooltip_text(Some(&gettext("Open Terminal")));
        terminal_btn.set_action_name(Some("win.open-terminal"));
        status_child.append(&terminal_btn);

        status_row.add_suffix(&status_child);
        status_group.add(&status_row);

        // Usage stats row
        let usage_row = adw::ActionRow::new();
        usage_row.set_title(&gettext("Resources"));
        usage_row.set_subtitle("CPU: 0.0% • Mem: 0.0MB / 0.0GB (0.0%)");
        status_group.add(&usage_row);

        let usage_query = container.usage();
        usage_query.connect_success(clone!(
            #[weak]
            usage_row,
            move |usage| {
                usage_row.set_subtitle(&format!(
                    "CPU: {} • Mem: {} ({})",
                    usage.cpu_perc, usage.mem_usage, usage.mem_perc
                ));
            }
        ));

        // Update the status row and fetch usage when the container's status
        // changes. The usage fetch is edge-triggered — only on the transition
        // *into* "up" — so reconciling the container list (which re-asserts the
        // same status) no longer aborts and restarts the usage fetch on every
        // pass.
        let on_status_change: Rc<dyn Fn()> = Rc::new({
            let container = container.clone();
            let prev_tag: Rc<RefCell<Option<String>>> = Rc::new(RefCell::new(None));
            move || {
                let detail = container.status_detail();
                let tag = container.status_tag();
                let prev = prev_tag.replace(Some(tag.clone()));
                status_row.set_subtitle(&format!("{tag}: {detail}"));
                stop_btn.set_visible(tag == "up");
                if tag == "up" && prev.as_deref() != Some("up") {
                    usage_query.fetch();
                }
            }
        });
        on_status_change();

        // Bind the notify handlers through a SignalGroup: it owns the handlers
        // and auto-disconnects them when this widget is finalized, so they
        // don't pile up on the (long-lived) container across overview
        // recreations.
        let signals = glib::SignalGroup::new::<Container>();
        for prop in ["status-detail", "status-tag"] {
            let on_change = on_status_change.clone();
            signals.connect_notify_local(Some(prop), move |_, _| on_change());
        }
        signals.set_target(Some(container));
        let _ = self.imp().signals.set(signals);

        // Quick Actions Group
        let actions_group = adw::PreferencesGroup::new();
        actions_group.set_title(&gettext("Quick Actions"));

        let upgrade_row = self.create_button_row(
            &gettext("Upgrade Container"),
            "software-update-available-symbolic",
            &gettext("Update all packages"),
            "win.upgrade-container",
        );
        actions_group.add(&upgrade_row);

        let apps_row = self.create_button_row(
            &gettext("Applications"),
            "view-list-bullet-symbolic",
            &gettext("Manage exportable applications"),
            "win.view-exportable-apps",
        );
        actions_group.add(&apps_row);

        if let Some(distro) = container.distro()
            && distro.package_manager().installable_file().is_some()
        {
            let install_package_row = self.create_button_row(
                &gettext("Install Package"),
                "package-symbolic",
                &gettext("Install packages into container"),
                "win.install-package",
            );
            actions_group.add(&install_package_row);
        }

        let clone_row = self.create_button_row(
            &gettext("Clone Container"),
            "edit-copy-symbolic",
            &gettext("Create a copy of this container"),
            "win.clone-container",
        );
        actions_group.add(&clone_row);

        // Danger Zone Group
        let danger_group = adw::PreferencesGroup::new();
        danger_group.set_title(&gettext("Danger Zone"));
        danger_group.add_css_class("danger-group");

        let delete_row = self.create_button_row(
            &gettext("Delete Container"),
            "user-trash-symbolic",
            &gettext("Permanently remove this container and all its data"),
            "win.delete-container",
        );
        delete_row.add_css_class("error");

        danger_group.add(&delete_row);

        // Add all groups to main box
        main_box.append(&self.build_container_header(container));
        main_box.append(&status_group);
        main_box.append(&actions_group);
        main_box.append(&danger_group);

        // Finish layout: the Overview page with Clamp inside ScrolledWindow
        clamp.set_child(Some(&main_box));
        scrolled_window.set_child(Some(&clamp));

        scrolled_window.upcast()
    }

    pub fn build_container_header(&self, container: &Container) -> gtk::Box {
        // Create labels for the title and subtitle
        let title_label = gtk::Label::new(Some(&container.name()));
        title_label.set_xalign(0.0);
        title_label.add_css_class("title-1");

        // Create image URL label
        let subtitle_label = gtk::Label::new(Some(&container.image()));
        subtitle_label.set_xalign(0.0);
        subtitle_label.set_ellipsize(pango::EllipsizeMode::Middle);
        subtitle_label.add_css_class("subtitle");

        // Create a copy button next to the image URL label
        let copy_btn = gtk::Button::from_icon_name("edit-copy-symbolic");
        copy_btn.set_tooltip_text(Some(&gettext("Copy image URL")));
        copy_btn.add_css_class("flat");
        copy_btn.add_css_class("xs");
        // Capture a clone of the image URL for the closure
        let image_url = container.image().to_string();
        let this = self.clone();
        copy_btn.connect_clicked(move |_| {
            if let Some(display) = gdk::Display::default() {
                let clipboard = display.clipboard();
                clipboard.set_text(&image_url);

                let parent_window: Option<DistroShelfWindow> = this
                    .ancestor(DistroShelfWindow::static_type())
                    .and_then(|w| w.downcast::<DistroShelfWindow>().ok());
                if let Some(win) = parent_window {
                    win.add_toast(adw::Toast::new(&gettext("Image URL copied")));
                }
            }
        });

        // Create a horizontal box that contains the subtitle label and copy button
        let subtitle_box = gtk::Box::new(gtk::Orientation::Horizontal, 6);
        subtitle_box.append(&subtitle_label);
        subtitle_box.append(&copy_btn);

        // Create a vertical box and add the title and the new subtitle_box
        let text_box = gtk::Box::new(gtk::Orientation::Vertical, 6);
        text_box.append(&title_label);
        text_box.append(&subtitle_box);

        // Add the text box and status label to the header box
        let icon = gtk::Image::new();
        icon.add_css_class("header-icon");
        icon.set_icon_size(gtk::IconSize::Large);

        let header_box = gtk::Box::new(gtk::Orientation::Horizontal, 12);
        header_box.add_css_class("distro-header");

        header_box.append(&icon);
        header_box.append(&text_box);

        if let Some(distro) = container.distro() {
            header_box.add_css_class(format!("distro-{}", distro.name()).as_str());
            icon.set_icon_name(Some(&distro.name()));
        }

        header_box
    }

    fn create_button_row(
        &self,
        title: &str,
        icon_name: &str,
        subtitle: &str,
        action_name: &str,
    ) -> adw::ActionRow {
        let row = adw::ActionRow::new();
        row.set_title(title);
        row.set_subtitle(subtitle);

        let icon = gtk::Image::from_icon_name(icon_name);
        row.add_prefix(&icon);
        row.set_activatable(true);
        row.set_action_name(Some(action_name));
        row
    }
}
