#!/usr/bin/env python

import gi
gi.require_version("Gdk", "4.0")
gi.require_version("Gtk", "4.0")
from gi.repository import GObject, Gio, Gtk
import os
from gettext import gettext as _
import gettext
try:
    from urllib.request import url2pathname
except ImportError:
    from urllib import url2pathname

from softwareproperties.gtk.utils import (
    setup_ui,
)

from aptsources.sourceslist import SourcesList, SourceEntryMatcher


# Holds `SourceItem` markup text for the GTK4's new Gio.ListMode.
class SourceItem(GObject.Object):
    def __init__(self, markup_text):
        super().__init__()
        self.markup_text = markup_text


class DialogAddSourcesList:
    def __init__(self, parent, sourceslist, source_renderer,
                 get_comparable, datadir, file):
        print(file)
        self.parent = parent
        self.source_renderer = source_renderer
        self.sourceslist = sourceslist
        self.get_comparable = get_comparable
        self.file = self.format_uri(file)

        setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-add-sources-list.ui"), domain="software-properties")

        self.dialog = self.dialog_add_sources_list
        self.label = self.label_sources
        self.listview = self.listview_sources
        self.scrolled = self.scrolled_window

        if self.parent is not None:
            self.dialog.set_transient_for(parent)
        else:
            self.dialog.set_title(_("Add Software Channels"))

        self.setup_model()

        # Parse the source.list file
        try:
            self.new_sources = SingleSourcesList(self.file)
        except:
            self.error()
            return

        # show the found channels or an error message
        if len(self.new_sources.list) > 0:
            counter = 0

            for source in self.new_sources.list:
                if source.invalid or source.disabled:
                    continue
                self.new_sources.matcher.match(source)
            # sort the list
            self.new_sources.list.sort(key=self.get_comparable)

            for source in self.new_sources.list:
                if source.invalid or source.disabled:
                    continue
                counter += 1
                line = self.source_renderer(source)
                source_item = SourceItem(line)
                self.store.append(source_item)
            if counter == 0:
                self.error()
                return

            header = gettext.ngettext("Install software additionally or "
                                      "only from this source?",
                                      "Install software additionally or "
                                      "only from these sources?",
                                      counter)
            body = _("You can either add the following sources or replace your "
                     "current sources by them. Only install software from "
                     "trusted sources.")
            self.label.set_markup("<big><b>%s</b></big>\n\n%s" % (header, body))
        else:
            self.error()
            return

    def setup_model(self):
        self.store = Gio.ListStore(item_type=SourceItem)
        self.selection_model = Gtk.NoSelection(model=self.store)
        self.listview.set_model(self.selection_model)

        factory = Gtk.SignalListItemFactory()
        factory.connect("setup", self._on_factory_setup)
        factory.connect("bind", self._on_factory_bind)
        factory.connect("unbind", self._on_factory_unbind)
        factory.connect("teardown", self._on_factory_teardown)
        self.listview.set_factory(factory)

    def _on_factory_setup(self, factory, list_item):
        label = Gtk.Label()
        label.set_use_markup(True)
        label.set_xalign(0.0)  # Left align
        label.set_margin_start(6)
        label.set_margin_end(6)
        label.set_margin_top(6)
        label.set_margin_bottom(6)
        list_item.set_child(label)

    def _on_factory_bind(self, factory, list_item):
        source_item = list_item.get_item()
        label = list_item.get_child()
        label.set_markup(source_item.markup_text)

    def _on_factory_unbind(self, factory, list_item):
        # Clear the label content when unbinding
        label = list_item.get_child()
        label.set_text("")

    def _on_factory_teardown(self, factory, list_item):
        pass

    def error(self):
        self.button_add.hide()
        self.button_cancel.set_label(_("Close"))
        self.button_replace.hide()
        self.scrolled.hide()
        header = _("There are no sources to install software from")
        body = _("The file '%s' does not contain any valid "
                 "software sources." % self.file)
        self.label.set_markup("%s\n\n<small>%s</small>" % (header, body))

    def present(self, on_response):
        def _on_response(_dlg, response_id):
            self.dialog.destroy()
            on_response(response_id, self.new_sources)
        self.dialog.connect("response", _on_response)
        self.dialog.present()

    def format_uri(self, uri):
        path = url2pathname(uri) # escape special chars
        path = path.strip('\r\n\x00') # remove \r\n and NULL
        if path.startswith('file:\\\\\\'): # windows
            path = path[8:] # 8 is len('file:///')
        elif path.startswith('file://'): #nautilus, rox
            path = path[7:] # 7 is len('file://')
        elif path.startswith('file:'): # xffm
            path = path[5:] # 5 is len('file:')
        return path

class SingleSourcesList(SourcesList):
    def __init__(self, file):
        self.matcher = SourceEntryMatcher("/usr/share/update-manager/channels/")
        self.list = []
        self.load(file)
