#!/usr/bin/env python3
"""
Main view for Debian Software Manager.

Author: Arjen Balfoort
Date: 2026-03-26
"""

import os
import glob
import gettext

from app_shared import (
    PackageState,
    PackageType,
    html_to_pango
)

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gdk, Pango  #pylint: disable=wrong-import-position

_ = gettext.translation('deb-software', fallback=True).gettext

class MainView:
    """Manages the UI: widgets, layout, and rendering."""

    def __init__(self, controller, model):
        self.controller = controller
        self.model = model

        # Load the UI file
        self.builder = Gtk.Builder.new_from_file(f'{model.script_dir}/deb-software.ui')

        # Main window and widgets
        self.window = self.builder.get_object('main_window')
        self.progressbar = self.builder.get_object('progressbar')
        self.notebook = self.builder.get_object('notebook')
        self.summary_sw = self.builder.get_object('summary_sw')
        self.summary_listbox = self.builder.get_object('summary_listbox')
        self.uptodate_box = self.builder.get_object('uptodate_box')
        self.updates_label = self.builder.get_object('updates_label')
        self.btn_favorites = self.builder.get_object('btn_favorites')
        self.btn_addons = self.builder.get_object('btn_addons')

        # Progress label
        self.progress_overlay = self.builder.get_object("progress_overlay")
        self.progress_label = Gtk.Label()
        self.progress_label.set_halign(Gtk.Align.START)
        self.progress_label.set_valign(Gtk.Align.CENTER)
        self.progress_label.add_css_class("progress_label")
        self.progress_label.set_ellipsize(Pango.EllipsizeMode.END)
        self.progress_overlay.add_overlay(self.progress_label)

        # Summary page
        self.sum_update = self.builder.get_object('sum_update')
        self.sum_update.set_visible(False)
        self.sum_title = self.builder.get_object('sum_title')

        # Detail page
        self.app_header = self.builder.get_object('app_header')
        self.app_logo = self.builder.get_object('app_logo')
        self.app_name = self.builder.get_object('app_name')
        self.app_installed = self.builder.get_object('app_installed')
        self.app_candidate = self.builder.get_object('app_candidate')
        self.app_size = self.builder.get_object('app_size')
        self.app_origin = self.builder.get_object('app_origin')
        self.app_screenshot = self.builder.get_object('app_screenshot')
        self.app_summary = self.builder.get_object('app_summary')
        self.app_homepage = self.builder.get_object('app_homepage')
        self.lbl_packages = self.builder.get_object('lbl_packages')
        self.app_packages = self.builder.get_object('app_packages')
        self.app_description = self.builder.get_object('app_description')

        # Detail page buttons
        self.app_back = self.builder.get_object('app_back')
        self.app_install = self.builder.get_object('app_install')
        self.app_update = self.builder.get_object('app_update')
        self.update_all_label = self.builder.get_object('update_all_label')
        self.app_remove = self.builder.get_object('app_remove')
        self.app_launch = self.builder.get_object('app_launch')

        # Settings
        self.save_settings = self.builder.get_object('save_settings')
        self.save_settings.set_visible(False)
        self.repo_row = None
        self.repo_checkbuttons = []
        self.flatpak_row = None
        self.flatpak_check = None
        self.interval_row = None
        self.interval_combo = None
        self.checker_row = None
        self.checker_check = None

        # Set window properties
        self.window.set_title(self.controller.app_name)
        self.window.set_icon_name(controller.get_application_id())

        # Load CSS
        self._load_css()

        # Connect signals
        self._connect_signals()

    def _load_css(self):
        """Load CSS styling."""
        display = Gdk.Display.get_default()
        css_path = os.path.join(self.model.script_dir, "style", f"{self.model.desktop}.css")
        css_paths = glob.glob(f"{self.model.save_dir}/*.css")
        if css_paths:
            css_path = css_paths[0]
        if not os.path.exists(css_path):
            css_path = os.path.join(self.model.script_dir, "style", "kde.css")

        css_provider = Gtk.CssProvider()
        css_provider.load_from_path(css_path)
        Gtk.StyleContext.add_provider_for_display(
            display,
            css_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    # --- UI Update Methods ---

    def set_progress(self, progress, message=""):
        """ Set the progress bar. """
        self.progressbar.set_fraction(progress / 100)
        if message:
            self.progress_label.set_text(message)

    def clear_progress(self):
        """ Clear the progress bar. """
        self.progressbar.set_fraction(0)
        self.progress_label.set_text("")

    def set_button_state(self, state: PackageState) -> None:
        """ Set the button state. """
        self.app_install.set_visible(False)
        self.app_remove.set_visible(False)
        self.app_update.set_visible(False)
        self.app_launch.set_visible(False)

        # FWUPD
        device = getattr(self.controller.selected_package, 'fwupd_device', None)
        if device:
            self.app_update.set_visible(True)
            return

        # Installed
        if state == PackageState.INSTALLED:
            if not self.controller.selected_package:
                return
            if self.controller.selected_package.package_type != PackageType.RUNTIME:
                self.app_remove.set_visible(True)
            if self.controller.selected_package.executable:
                self.app_launch.set_visible(True)
            if self.controller.selected_package.is_updatable:
                self.app_update.set_visible(True)
            return

        # Updated
        if state == PackageState.UPDATED:
            if not self.controller.selected_package:
                return
            if self.controller.selected_package.package_type != PackageType.RUNTIME:
                self.app_remove.set_visible(True)
            if self.controller.selected_package.executable:
                self.app_launch.set_visible(True)
            return

        # Available (or removed)
        self.app_install.set_visible(True)

    def add_app_summary(self, pk_info):
        """Add a package summary to the list."""
        package_box = self.model.software_view.get_gtk_box_summary(pk_info)
        click_gesture = Gtk.GestureClick()
        click_gesture.connect("pressed", self.controller.on_summary_clicked, pk_info)
        package_box.add_controller(click_gesture)
        self.summary_listbox.append(package_box)

    def show_no_updates(self):
        """Show message when no updates are available."""
        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)
        box.set_spacing(24)
        box.add_css_class('uptodate_box')

        icon_path = os.path.join(self.model.images_dir, "uptodate.svg")
        icon = Gtk.Picture()
        self.model.image_handler.set_picture(icon, icon_path, 64)
        icon.set_content_fit(Gtk.ContentFit.SCALE_DOWN)
        icon.set_valign(Gtk.Align.CENTER)
        box.append(icon)

        update_label = Gtk.Label()
        update_label.set_label(_("Your system is up to date"))
        update_label.set_halign(Gtk.Align.CENTER)
        update_label.set_valign(Gtk.Align.CENTER)
        box.append(update_label)

        listbox_row = Gtk.ListBoxRow()
        listbox_row.set_child(box)
        listbox_row.add_css_class("listbox-row")
        self.summary_listbox.append(listbox_row)

    def show_package_details(self, pk_info):
        """Display details for a selected package."""
        self.controller.selected_package = pk_info
        self.controller.selected_screenshot = 0

        if pk_info.is_installed:
            self.set_button_state(PackageState.INSTALLED)
        else:
            self.set_button_state(PackageState.AVAILABLE)

        self.model.image_handler.set_picture(self.app_logo, pk_info.icon, 128)
        self.app_name.set_label(pk_info.name)
        self.app_installed.set_label(str(pk_info.version))
        self.app_candidate.set_label(pk_info.candidate_version)
        self.app_size.set_label(pk_info.installed_size)
        self.app_origin.set_label(pk_info.origin)

        # Homepage
        self.app_homepage.set_visible(False)
        if pk_info.homepage:
            self.app_homepage.set_visible(True)
            self.app_homepage.set_markup(
                f"<a href='{pk_info.homepage}'>{pk_info.homepage}</a>"
            )
            self.app_homepage.set_use_markup(True)

        # Background color
        self.model.image_handler.set_widget_background_color_from_image(
            widget=self.app_header,
            image_path=pk_info.icon,
            transparency=0.1
        )

        # Screenshot
        self.app_screenshot.set_visible(False)
        if pk_info.screenshots:
            for screenshot_url in pk_info.screenshots:
                img = self.model.image_handler.load_image_from_url(
                    self.model.cache_dir, screenshot_url
                )
                if img is not None:
                    self.app_screenshot.set_visible(True)
                    self.app_screenshot.set_paintable(img)
                    if len(pk_info.screenshots) > 1:
                        hand_cursor = Gdk.Cursor.new_from_name("pointer", None)
                        self.app_screenshot.set_cursor(hand_cursor)
                    break

        self.app_summary.set_label(pk_info.summary)
        buffer = Gtk.TextBuffer()
        buffer.set_text(html_to_pango(pk_info.description))
        self.app_description.set_buffer(buffer)

        # Show package list
        if pk_info.is_installed:
            self.lbl_packages.set_visible(False)
            self.app_packages.set_visible(False)
        else:
            self.lbl_packages.set_visible(True)
            self.app_packages.set_visible(True)
            self.app_packages.set_label('\n'.join([
                pk_info.package_name or pk_info.package_id
            ] + pk_info.additional_packages))

        self.notebook.set_current_page(1)

    def _connect_signals(self):
        """Connect all static button signals to the controller."""
        # Category buttons (left sidebar)
        self.btn_favorites.connect('clicked', self.controller.on_button_clicked, 'favorites')
        self.btn_addons.connect('clicked', self.controller.on_button_clicked, 'addons')

        # Other category buttons (from the .ui file)
        btn_installed = self.builder.get_object('btn_installed')
        btn_installed.connect('clicked', self.controller.on_button_clicked, 'installed')

        btn_updates = self.builder.get_object('btn_updates')
        btn_updates.connect('clicked', self.controller.on_button_clicked, 'updates')

        btn_accessibility = self.builder.get_object('btn_accessibility')
        btn_accessibility.connect('clicked', self.controller.on_button_clicked, 'accessibility')

        btn_settings = self.builder.get_object('btn_settings')
        btn_settings.connect('clicked', self.controller.on_button_clicked, 'settings')

        # Toolbar buttons
        btn_log = self.builder.get_object('btn_log')
        btn_log.connect('clicked', self.controller.on_button_log_clicked)

        btn_help = self.builder.get_object('btn_help')
        btn_help.connect('clicked', self.controller.on_button_help_clicked)

        btn_about = self.builder.get_object('btn_about')
        btn_about.connect('clicked', self.controller.on_button_about_clicked)

        btn_refresh = self.builder.get_object('btn_refresh')
        btn_refresh.connect('clicked', self.controller.on_button_refresh_clicked)

        # Search entry
        search_entry = self.builder.get_object('search_entry')
        search_entry.connect("activate", self.controller.on_search_activate)
        search_entry.connect('icon-release', self.controller.on_clear_search)

        # Detail page buttons
        self.sum_update.connect('clicked', self.controller.on_update_all_clicked)
        self.save_settings.connect('clicked', self.controller.on_save_settings_button_clicked)
        self.app_back.connect('clicked', self.controller.on_app_back_clicked)
        self.app_install.connect('clicked', self.controller.on_app_install_clicked)
        self.app_remove.connect('clicked', self.controller.on_app_remove_clicked)
        self.app_update.connect('clicked', self.controller.on_app_update_clicked)
        self.app_launch.connect('clicked', self.controller.on_app_launch_clicked)

        # Screenshot click gesture
        gesture = Gtk.GestureClick()
        gesture.connect("pressed", self.controller.on_screenshot_clicked)
        self.app_screenshot.add_controller(gesture)

    def build_category_buttons(self):
        """Build the category buttons in the sidebar."""
        left_pane = self.builder.get_object('left_pane')
        sibling = self.builder.get_object('separator')

        args_category = (self.model.parser_args.category.strip().lower()
                         if self.model.parser_args and self.model.parser_args.category else '')

        button_action = None
        for category in self.model.software_manager.categories:
            button = Gtk.Button()
            button.connect('clicked', self.controller.on_button_clicked, category)

            if args_category == category.lower():
                button_action = (button, category)

            box = Gtk.Box(spacing=10)
            icon = Gtk.Picture()
            icon.set_can_shrink(False)
            icon.set_content_fit(Gtk.ContentFit.SCALE_DOWN)
            icon_path = f"/usr/lib/deb-software/images/menu/{category.split(' ')[0].lower()}.svg"
            if os.path.exists(icon_path):
                self.model.image_handler.set_picture(icon, icon_path, 16)
            else:
                self.model.image_handler.set_picture(
                    icon, f"applications-{category.split(' ')[0].lower()}", 16
                )

            box.append(icon)
            box.append(Gtk.Label(label=self.model.get_category_translation(category)))
            button.set_child(box)

            left_pane.insert_child_after(button, sibling)
            sibling = button

        self.btn_addons.set_visible(True)

        if button_action:
            self.controller.on_button_clicked(*button_action)
        elif args_category == 'updates' or \
            (self.model.parser_args and self.model.parser_args.update):
            self.controller.on_button_clicked(self.builder.get_object('btn_updates'), 'updates')
        elif args_category == 'installed':
            self.controller.on_button_clicked(self.builder.get_object('btn_installed'), 'installed')
        else:
            self.controller.on_button_clicked(self.builder.get_object('btn_favorites'), 'favorites')

    @staticmethod
    def get_button_text(button: Gtk.Button) -> str:
        """ Return the text of a button. """
        box = button.get_child()
        if box is None:
            label = button.get_label()
            return label if label else ''
        child = box.get_first_child()
        while child is not None:
            if isinstance(child, Gtk.Label):
                return child.get_text()
            child = child.get_next_sibling()
        return ''
