# -*- coding: UTF-8 -*-
# based on: https://github.com/gnunn1/tilix/blob/master/data/nautilus/open-tilix.py

from gettext import gettext, textdomain
from subprocess import call

try:
    from urllib import unquote  # type: ignore

    from urlparse import urlparse
except ImportError:
    from urllib.parse import unquote, urlparse

from gi import require_version

try:
    require_version("Gtk", "4.0")
    require_version("Nautilus", "4.0")
except ValueError:
    require_version("Gtk", "3.0")
    require_version("Nautilus", "3.0")

from gi.repository import Gio, GObject, Gtk, Nautilus  # noqa: E402

TERM_WORKDIR_PARAMS = {
    "alacritty": "--working-directory ",
    "blackbox": "--working-directory ",
    "cool-retro-term": "--workdir ",
    "deepin-terminal": "--work-directory ",
    "foot": "--working-directory=",
    "footclient": "--working-directory=",
    "gnome-terminal": "--working-directory=",
    "guake": "guake --show --new-tab=",
    "hyper": "",
    "kermit": "-w ",
    "kgx": "--working-directory=",
    "kitty": "--directory ",
    "konsole": "--workdir ",
    "mate-terminal": "--working-directory=",
    "mlterm": "--working-directory=",
    "qterminal": "--workdir ",
    "sakura": "-d ",
    "st": "-d ",
    "terminator": "--working-directory=",
    "terminology": "--current-directory ",
    "termite": "-d ",
    "tilix": "-w ",
    "urxvt": "-cd ",
    "urxvtc": "-cd ",
    "wezterm": "start --cwd ",
    "xfce4-terminal": "--working-directory=",
    "tabby": "open ",
}

NEW_TAB_PARAMS = {
    "alacritty": None,
    "blackbox": None,
    "cool-retro-term": None,
    "deepin-terminal": None,
    "foot": None,
    "footclient": None,
    "gnome-terminal": "--tab",
    "guake": None,
    "hyper": None,
    "kermit": None,
    "kgx": "--tab",
    "kitty": None,
    "konsole": "--new-tab",
    "mate-terminal": "--tab",
    "mlterm": None,
    "qterminal": None,
    "sakura": None,
    "st": None,
    "terminator": "--new-tab",
    "terminology": None,
    "termite": None,
    "tilix": None,
    "urxvt": None,
    "urxvtc": None,
    "wezterm": None,
    "xfce4-terminal": "--tab",
    "tabby": None,
}

TERM_CMD_PARAMS = {
    "alacritty": "-e",
    "blackbox": "-c",
    "cool-retro-term": "-e",
    "deepin-terminal": "-e",
    "foot": "-e",
    "footclient": "-e",
    "gnome-terminal": "-e",
    "guake": "-e",
    "hyper": "-e",
    "kermit": "-e",
    "kgx": "-e",
    "kitty": "-e",
    "konsole": "-e",
    "mate-terminal": "-e",
    "mlterm": "-e",
    "qterminal": "-e",
    "sakura": "-e",
    "st": "-e",
    "terminator": "-e",
    "terminology": "-e",
    "termite": "-e",
    "tilix": "-e",
    "urxvt": "-e",
    "urxvtc": "-e",
    "wezterm": "-e",
    "xfce4-terminal": "-e",
    "tabby": "-e",
}

FLATPAK_PARMS = ["off", "system", "user"]

FLATPAK_NAMES = {
    "blackbox": "com.raggesilver.BlackBox",
    "tilix": "com.gexperts.Tilix",
}

global terminal
terminal = "blackbox"
terminal_cmd = "/usr/bin/blackbox-terminal"
new_tab = False
flatpak = FLATPAK_PARMS[0]
GSETTINGS_PATH = "com.github.stunkymonkey.nautilus-open-any-terminal"
GSETTINGS_KEYBINDINGS = "keybindings"
GSETTINGS_TERMINAL = "terminal"
GSETTINGS_NEW_TAB = "new-tab"
GSETTINGS_FLATPAK = "flatpak"
REMOTE_URI_SCHEME = ["ftp", "sftp"]
textdomain("nautilus-open-any-terminal")
_ = gettext


def _checkdecode(s):
    """Decode string assuming utf encoding if it's bytes, else return unmodified"""
    return s.decode("utf-8") if isinstance(s, bytes) else s


def open_terminal_in_file(filename):
    """open the new terminal with correct path"""
    if filename:
        # escape filename quotations
        filename = filename.replace('"', '\\"')
        if new_tab:
            call(
                '{0} {1} {2}"{3}" &'.format(
                    terminal_cmd,
                    NEW_TAB_PARAMS[terminal],
                    TERM_WORKDIR_PARAMS[terminal],
                    filename,
                ),
                shell=True,
            )
        else:
            call(
                '{0} {1}"{2}" &'.format(
                    terminal_cmd, TERM_WORKDIR_PARAMS[terminal], filename
                ),
                shell=True,
            )
    else:
        call("{0} &".format(terminal_cmd), shell=True)


def set_terminal_args(*args):
    global new_tab
    global flatpak
    global terminal_cmd
    value = _gsettings.get_string(GSETTINGS_TERMINAL)
    newer_tab = _gsettings.get_boolean(GSETTINGS_NEW_TAB)
    flatpak = FLATPAK_PARMS[_gsettings.get_enum(GSETTINGS_FLATPAK)]
    if value in TERM_WORKDIR_PARAMS:
        global terminal
        terminal = value
        if newer_tab and NEW_TAB_PARAMS[terminal] is not None:
            new_tab = newer_tab
            new_tab_text = "opening in a new tab"
        else:
            new_tab_text = "opening a new window"
        if newer_tab and NEW_TAB_PARAMS[terminal] is None:
            new_tab_text += " (terminal does not support tabs)"
        if flatpak != FLATPAK_PARMS[0] and value in FLATPAK_NAMES:
            terminal_cmd = "flatpak run --{0} {1}".format(
                flatpak, FLATPAK_NAMES[terminal]
            )
            flatpak_text = "with flatpak as {0}".format(flatpak)
        else:
            terminal_cmd = terminal
            flatpak = FLATPAK_PARMS[0]
            flatpak_text = ""
        print(
            'open-any-terminal: terminal is set to "{0}" {1} {2}'.format(
                terminal, new_tab_text, flatpak_text
            )
        )
    else:
        print('open-any-terminal: unknown terminal "{0}"'.format(value))


if Nautilus._version == "3.0":

    class OpenAnyTerminalShortcutProvider(
        GObject.GObject, Nautilus.LocationWidgetProvider
    ):
        def __init__(self):
            source = Gio.SettingsSchemaSource.get_default()
            if source.lookup(GSETTINGS_PATH, True):
                self._gsettings = Gio.Settings.new(GSETTINGS_PATH)
                self._gsettings.connect("changed", self._bind_shortcut)
                self._create_accel_group()
            self._window = None
            self._uri = None

        def _create_accel_group(self):
            self._accel_group = Gtk.AccelGroup()
            shortcut = self._gsettings.get_string(GSETTINGS_KEYBINDINGS)
            key, mod = Gtk.accelerator_parse(shortcut)
            self._accel_group.connect(
                key, mod, Gtk.AccelFlags.VISIBLE, self._open_terminal
            )

        def _bind_shortcut(self, gsettings, key):
            if key == GSETTINGS_KEYBINDINGS:
                self._accel_group.disconnect(self._open_terminal)
                self._create_accel_group()

        def _open_terminal(self, *args):
            filename = unquote(self._uri[7:])
            open_terminal_in_file(filename)

        def get_widget(self, uri, window):
            self._uri = uri
            if self._window:
                self._window.remove_accel_group(self._accel_group)
            if self._gsettings:
                window.add_accel_group(self._accel_group)
            self._window = window
            return None


class OpenAnyTerminalExtension(GObject.GObject, Nautilus.MenuProvider):
    def _open_terminal(self, file_):
        if file_.get_uri_scheme() in REMOTE_URI_SCHEME:
            result = urlparse(file_.get_uri())
            if result.username:
                value = "ssh -t {0}@{1}".format(result.username, result.hostname)
            else:
                value = "ssh -t {0}".format(result.hostname)
            if result.port:
                value = "{0} -p {1}".format(value, result.port)
            if file_.is_directory():
                value = '{0} cd "{1}" \\; $SHELL'.format(value, result.path)

            call(
                '{0} {1} "{2}" &'.format(
                    terminal_cmd, TERM_CMD_PARAMS[terminal], value
                ),
                shell=True,
            )
        else:
            filename = Gio.File.new_for_uri(file_.get_uri()).get_path()
            open_terminal_in_file(filename)

    def _menu_activate_cb(self, menu, file_):
        self._open_terminal(file_)

    def _menu_background_activate_cb(self, menu, file_):
        self._open_terminal(file_)

    def get_file_items(self, *args):
        # `args` will be `[files: List[Nautilus.FileInfo]]` in Nautilus 4.0 API,
        # and `[window: Gtk.Widget, files: List[Nautilus.FileInfo]]` in Nautilus 3.0 API.

        files = args[-1]

        if len(files) != 1:
            return
        items = []
        file_ = files[0]

        if file_.is_directory():

            if file_.get_uri_scheme() in REMOTE_URI_SCHEME:
                uri = _checkdecode(file_.get_uri())
                item = Nautilus.MenuItem(
                    name="NautilusPython::open_remote_item",
                    label=_("Open Remote {}").format(terminal.title()),
                    tip=_("Open Remote {} In {}").format(terminal.title(), uri),
                )
                item.connect("activate", self._menu_activate_cb, file_)
                items.append(item)

            filename = _checkdecode(file_.get_name())
            item = Nautilus.MenuItem(
                name="NautilusPython::open_file_item",
                label=_("Open In {}").format(terminal.title()),
                tip=_("Open {} In {}").format(terminal.title(), filename),
            )
            item.connect("activate", self._menu_activate_cb, file_)
            items.append(item)

        return items

    def get_background_items(self, *args):
        # `args` will be `[folder: Nautilus.FileInfo]` in Nautilus 4.0 API,
        # and `[window: Gtk.Widget, file: Nautilus.FileInfo]` in Nautilus 3.0 API.

        file_ = args[-1]

        items = []
        if file_.get_uri_scheme() in REMOTE_URI_SCHEME:
            item = Nautilus.MenuItem(
                name="NautilusPython::open_bg_remote_item",
                label=_("Open Remote {} Here").format(terminal.title()),
                tip=_("Open Remote {} In This Directory").format(terminal.title()),
            )
            item.connect("activate", self._menu_activate_cb, file_)
            items.append(item)

        item = Nautilus.MenuItem(
            name="NautilusPython::open_bg_file_item",
            label=_("Open {} Here").format(terminal.title()),
            tip=_("Open {} In This Directory").format(terminal.title()),
        )
        item.connect("activate", self._menu_background_activate_cb, file_)
        items.append(item)
        return items


source = Gio.SettingsSchemaSource.get_default()
if source is not None and source.lookup(GSETTINGS_PATH, True):
    _gsettings = Gio.Settings.new(GSETTINGS_PATH)
    _gsettings.connect("changed", set_terminal_args)
    set_terminal_args()
