# -*- 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 re
import gettext

# External libraries
import gi
from tblock.converter import ADBLOCKPLUS, DNSMASQ, HOSTS, LIST, TBLOCK, TBLOCK_LEGACY

# Local libraries
from .error import ErrorActivity
from ._polkit import pk_dummy_authenticate
from .job import JobController
from .const import ALL_SYNTAX_READABLE, ExitStatusCode

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 CustomAddActivity:
    """
    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("CustomAddActivity")
        self.window.set_application(self._application)

        self._syntax = None

        self._store = Gtk.ListStore(str, str)
        # pylint: disable=consider-using-dict-items
        for syntax in ALL_SYNTAX_READABLE:
            self._store.append([syntax, ALL_SYNTAX_READABLE[syntax]])
        self._combo = Gtk.ComboBox.new_with_model(self._store)
        self._combo.connect("changed", self.__select_syntax)

        self.threaded_activity = JobController(
            application=self._application,
            status_label=self._application.builder.get_object(
                "CustomAddActivityStatusLabel"
            ),
            status_bar=self._application.builder.get_object(
                "CustomAddActivityStatusBar"
            ),
            finish_button=self._application.builder.get_object(
                "CustomAddActivityFinishButton"
            ),
        )

        self._build_combo()

    def _build_combo(self) -> None:
        """
        Build the combo box containing available filter list formats
        This function should not be executed directly outside this class
        """
        renderer_text = Gtk.CellRendererText()
        self._combo.pack_start(renderer_text, True)
        self._combo.add_attribute(renderer_text, "text", 1)
        self._combo.set_active(0)
        self._application.builder.get_object("CustomAddActivityContainer").add(
            self._combo
        )
        self.__select_syntax(self._combo)

    def start(self) -> None:
        """
        Start the activity
        """
        self._application.builder.get_object("CustomAddSource").set_text("")
        self._application.builder.get_object("CustomAddId").set_text("")
        self.go_to_page(0)
        self.window.show_all()

    def __select_syntax(self, combo) -> None:
        """
        Handler for when a filter list format is selected in the combo box

        :param combo:
        """
        syntax_label = self._application.builder.get_object(
            "CustomAddActivitySyntaxLabel"
        )
        tree_iter = combo.get_active_iter()
        model = combo.get_model()
        row_id = model[tree_iter][:2][0]
        self._syntax = row_id
        if row_id is None:
            syntax_label.set_text(
                _(
                    "Choose this if you are not sure. Note that it may take more time than usual."
                )
            )
        elif row_id == ADBLOCKPLUS:
            syntax_label.set_text(
                _(
                    "The default format used in most browser add-ons. TBlock supports it partially only."
                )
            )
        elif row_id == DNSMASQ:
            syntax_label.set_text(
                _(
                    "Import your dnsmasq.conf rules into TBlock. This format is partially supported."
                )
            )
        elif row_id == HOSTS:
            syntax_label.set_text(
                _(
                    "Import your /etc/hosts rules into TBlock. This format is fully supported."
                )
            )
        elif row_id == LIST:
            syntax_label.set_text(
                _(
                    "A simple list of domains to block. TBlock has native support for it."
                )
            )
        elif row_id == TBLOCK:
            syntax_label.set_text(
                _("The official format that is fully supported by TBlock.")
            )
        elif row_id == TBLOCK_LEGACY:
            syntax_label.set_text(
                _(
                    "This format is deprecated and support will be removed in future versions."
                )
            )
        else:
            syntax_label.set_text("")

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

        :param index: The index of the page to go to
        """
        if (
            index == 1
            and self._application.builder.get_object("CustomAddSource").get_text() == ""
        ):
            self._application.error_window.raise_invalid_source_error()
        elif (
            index == 2
            and self._application.builder.get_object("CustomAddId").get_text() == ""
        ):
            self._application.error_window.raise_invalid_id_error()
        else:
            self._application.builder.get_object(
                "CustomAddActivityStack"
            ).set_visible_child_name(f"CustomAddActivityPage{index}")

    def edit_id_field(self):
        """
        Replace unwanted characters in the filter list ID
        """
        id_field = self._application.builder.get_object("CustomAddId")
        output = ""
        for _i in id_field.get_text().lower():
            if _i == " ":
                output += "-"
            elif re.match(r"^[a-z0-9_\-]$", _i):
                output += _i
        id_field.set_text(output)

    def select_file(self) -> None:
        """
        Start a FileChooserDialog to select a file
        """
        dialog = Gtk.FileChooserDialog(
            title=_("Please choose a file"),
            action=Gtk.FileChooserAction.OPEN,
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, _("Select"), Gtk.ResponseType.OK
        )
        dialog.set_default_size(800, 400)
        filter_text = Gtk.FileFilter()
        filter_text.set_name(_("Text files"))
        filter_text.add_mime_type("text/plain")
        filter_any = Gtk.FileFilter()
        filter_any.set_name(_("Any files"))
        filter_any.add_pattern("*")
        dialog.add_filter(filter_text)
        dialog.add_filter(filter_any)
        # pylint: disable=no-member
        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self._application.builder.get_object("CustomAddSource").set_text(
                # pylint: disable=no-member
                dialog.get_uri()
            )
        dialog.destroy()

    def run_thread(self) -> None:
        """
        Run the setup operation
        """
        _auth_err_code = pk_dummy_authenticate()
        if _auth_err_code == ExitStatusCode.NO_ERROR:
            self.go_to_page(2)
            source = self._application.builder.get_object("CustomAddSource").get_text()
            if source[-len(source) : -len(source) + 7] == "file://":
                source = source.split("file://")[1]
            self.threaded_activity.add_custom_filter_list(
                id_=self._application.builder.get_object("CustomAddId").get_text(),
                source=source,
                syntax=self._syntax,
            )
        else:
            ErrorActivity(self._application.builder).handle_error(_auth_err_code)

    def quit(self, index: int = None) -> None:
        """
        Quit the activity
        :param index: Do not quit the activity, go to page number {index} instead
        """
        if self.threaded_activity.running:
            self.threaded_activity.kill()
        if index is None:
            self.window.hide()
        else:
            self.go_to_page(index)
