# -*- coding: utf-8 -*-
#  _____  ____   _               _
# |_   _|| __ ) | |  ___    ___ | | __
#   | |  |  _ \ | | / _ \  / __|| |/ /
#   | |  | |_) || || (_) || (__ |   <
#   |_|  |____/ |_| \___/  \___||_|\_\
#
# Copyright (C) 2021-2025 Camelia Lavender <camelia@tblock.me>

# 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/>.$

# Standard libraries
import gettext

# External libraries
import tblock
import tblock.utils
import tblock.exceptions
import gi

# Local libraries
from .const import policies, ExitStatusCode
from ._polkit import pk_subprocess_run, pk_dummy_authenticate

gi.require_version("Gtk", "3.0")
# pylint: disable=wrong-import-position,wrong-import-order
from gi.repository import Gtk

gettext.textdomain("tblock-gui")
_ = gettext.gettext


class RulesActivity:
    """
    Class that interacts with the activity of the same name from the glade UI
    """

    def __init__(self, application) -> None:
        """
        Initiate the activity

        :param application: An object of type Gtk.Application
        """
        self._application = application
        self.window = self._application.builder.get_object("RulesActivity")
        self.window.set_application(self._application)

        self._treeview = None
        self._store = Gtk.ListStore(bool, str, str, str)
        self._total_rules = 0
        self._rules_to_delete = []

        agr = Gtk.AccelGroup()
        self.window.add_accel_group(agr)
        key, modifier = Gtk.accelerator_parse("<Control>A")
        agr.connect(key, modifier, Gtk.AccelFlags.VISIBLE, self.__select_all_rules)

        # This is not needed since the stack widget is no longer used in this window
        # self.threaded_activity = JobController(
        #    status_label=self.builder.get_object("RulesActivityStatusLabel"),
        #    status_bar=self.builder.get_object("RulesActivityStatusBar"),
        #    finish_button=self.builder.get_object("RulesActivityFinishButton"),
        #    return_button=self.builder.get_object("RulesActivityGobackButton"),
        # )

    def start(self) -> None:
        """
        Start the activity
        """
        self.refresh()
        self.go_to_page("chooser")
        self.window.show_all()
        self._application.builder.get_object("RulesActivityDeleteButton").hide()

    def refresh(self) -> None:
        """
        Refresh the activity
        """
        container = self._application.builder.get_object("RulesContainer")
        self._total_rules = 0
        self._rules_to_delete.clear()
        if self._treeview is not None:
            container.remove(self._treeview)
            self._treeview = None
        self._store = Gtk.ListStore(bool, str, str, str)
        for i in tblock.get_all_rules(user_only=True):
            _r = tblock.Rule(i)
            if _r.policy == tblock.REDIRECT:
                self._store.append([False, i, policies[_r.policy], _r.ip])
            else:
                self._store.append([False, i, policies[_r.policy], ""])
            self._total_rules += 1
        self._treeview = Gtk.TreeView(model=self._store)
        renderer_toggle = Gtk.CellRendererToggle()
        renderer_toggle.connect("toggled", self.__select_rule)
        column_toggle = Gtk.TreeViewColumn(_("Select"), renderer_toggle, active=0)
        self._treeview.append_column(column_toggle)
        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn(_("Domain"), renderer_text, text=1)
        self._treeview.append_column(column_text)
        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn(_("Policy"), renderer_text, text=2)
        self._treeview.append_column(column_text)
        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn(_("IP address"), renderer_text, text=3)
        self._treeview.append_column(column_text)
        container.add(self._treeview)
        self._treeview.show()
        # This is required when a rule is added and others are already selected
        # Otherwise the "Delete" button is not hidden
        self._application.builder.get_object("RulesActivityDeleteButton").hide()

    def __select_all_rules(self, *_args):
        """
        Handler for when all rules are selected

        :param _args:
        """
        i = 0
        if self._total_rules == len(self._rules_to_delete):
            for _x in self._store:
                self.__select_rule(None, i)
                i += 1
        else:
            for _x in self._store:
                self._store[i][0] = True
                if not self._store[i][1] in self._rules_to_delete:
                    self._rules_to_delete.append(self._store[i][1])
                i += 1
            self._application.builder.get_object("RulesActivityDeleteButton").show()

    def __select_rule(self, __widget, path) -> None:
        """
        Handler for when a rule is selected

        :param __widget:
        :param path:
        """
        self._store[path][0] = not self._store[path][0]
        if self._store[path][1] in self._rules_to_delete:
            self._rules_to_delete.remove(self._store[path][1])
        else:
            self._rules_to_delete.append(self._store[path][1])
        if self._rules_to_delete:
            self._application.builder.get_object("RulesActivityDeleteButton").show()
        else:
            self._application.builder.get_object("RulesActivityDeleteButton").hide()

    def go_to_page(self, name: str) -> None:
        """
        Go to a selected page of the activity

        :param name: The index of the page to go to
        """
        self._application.builder.get_object(
            "RulesActivityStack"
        ).set_visible_child_name(name)

    def run_thread(self) -> None:
        """
        Run the rule adding/deleting operation
        """
        _auth_err_code = pk_dummy_authenticate()
        if _auth_err_code == ExitStatusCode.NO_ERROR:
            if not tblock.utils.db_is_locked():
                if (
                    pk_subprocess_run(["delete"] + self._rules_to_delete)
                    != ExitStatusCode.NO_ERROR
                ):
                    self._application.error_window.raise_error(
                        _("Failed to delete rules")
                    )
                self.refresh()
            else:
                self._application.error_window.raise_db_locked_error()
        else:
            self._application.error_window.handle_error(_auth_err_code)

    def quit(self) -> None:
        """
        Quit the activity
        """
        self.window.hide()
