# -*- coding: utf-8 -*-

import logging
import os
import subprocess
import sys

from atomicwrites import atomic_write
from PyQt5.QtCore import QCoreApplication, QMetaType, QUrl, QVariant
from PyQt5.QtGui import QClipboard, QDesktopServices

if sys.platform == "win32":
    from win32com.client import Dispatch  # pylint: disable=import-error

from gridsync import resource, settings, APP_NAME, autostart_file_path


def _dbus_notify(title, message, duration=5000):
    from PyQt5.QtDBus import (
        QDBus,
        QDBusArgument,
        QDBusConnection,
        QDBusInterface,
    )

    bus = QDBusConnection.sessionBus()
    if not bus.isConnected():
        raise OSError("Could not connect to DBus")
    interface = QDBusInterface(
        "org.freedesktop.Notifications",
        "/org/freedesktop/Notifications",
        "org.freedesktop.Notifications",
        bus,
    )
    error = interface.lastError()
    if error.type():
        raise RuntimeError("{}; {}".format(error.name(), error.message()))
    # See https://developer.gnome.org/notification-spec/
    # "This allows clients to effectively modify the notification while
    # it's active. A value of value of 0 means that this notification
    # won't replace any existing notifications."
    replaces_id = QVariant(0)
    replaces_id.convert(QVariant.UInt)
    interface.call(
        QDBus.NoBlock,
        "Notify",
        APP_NAME,
        replaces_id,
        resource(settings["application"]["tray_icon"]),
        title,
        message,
        QDBusArgument([], QMetaType.QStringList),
        {},
        duration,
    )


def notify(systray, title, message, duration=5000):
    logging.debug("Sending desktop notification...")
    if sys.platform.startswith("linux"):
        try:
            _dbus_notify(title, message, duration)
        except (OSError, RuntimeError) as err:
            logging.warning("%s; falling back to showMessage()...", str(err))
            systray.showMessage(title, message, msecs=duration)
    else:
        systray.showMessage(title, message, msecs=duration)


def _desktop_open(path):
    QDesktopServices.openUrl(QUrl.fromLocalFile(path))


def open_enclosing_folder(path):
    path = os.path.expanduser(path)
    if sys.platform == "darwin":
        subprocess.Popen(["open", "--reveal", path])
    elif sys.platform == "win32":
        subprocess.Popen('explorer /select,"{}"'.format(path))
    else:
        # TODO: Get file-manager via `xdg-mime query default inode/directory`
        # and, if 'org.gnome.Nautilus.desktop', call `nautilus --select`?
        _desktop_open(os.path.dirname(path))


def open_path(path):
    path = os.path.expanduser(path)
    if sys.platform == "darwin":
        subprocess.Popen(["open", path])
    elif sys.platform == "win32":
        os.startfile(path)
    else:
        _desktop_open(path)


def get_clipboard_modes():
    clipboard = QCoreApplication.instance().clipboard()
    modes = [QClipboard.Clipboard]
    if clipboard.supportsSelection():
        modes.append(QClipboard.Selection)
    if clipboard.supportsFindBuffer():
        modes.append(QClipboard.FindBuffer)
    return modes


def get_clipboard_text(mode=QClipboard.Clipboard):
    return QCoreApplication.instance().clipboard().text(mode)


def set_clipboard_text(text, mode=QClipboard.Clipboard):
    QCoreApplication.instance().clipboard().setText(text, mode)
    logging.debug(
        "Copied %i bytes to clipboard %i", len(text) if text else 0, mode
    )


def _autostart_enable_linux(executable):
    with atomic_write(autostart_file_path, mode="w", overwrite=True) as f:
        f.write(
            """\
[Desktop Entry]
Name={0}
Comment={0}
Type=Application
Exec=env PATH={1} {2}
Terminal=false
""".format(
                APP_NAME, os.environ["PATH"], executable
            )
        )


# pylint: disable=line-too-long
def _autostart_enable_mac(executable):
    with atomic_write(autostart_file_path, mode="w", overwrite=True) as f:
        f.write(
            """\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>EnvironmentVariables</key>
    <dict>
      <key>PATH</key>
      <string>{}</string>
    </dict>
    <key>Label</key>
    <string>{}</string>
    <key>Program</key>
    <string>{}</string>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>
""".format(
                os.environ["PATH"],
                settings["build"]["mac_bundle_identifier"],
                executable,
            )
        )


def _autostart_enable_windows(executable):
    shell = Dispatch("WScript.Shell")
    shortcut = shell.CreateShortCut(autostart_file_path)
    shortcut.Targetpath = executable
    shortcut.WorkingDirectory = os.path.dirname(executable)
    shortcut.save()


def autostart_enable():
    logging.debug("Writing autostart file to '%s'...", autostart_file_path)
    try:
        os.makedirs(os.path.dirname(autostart_file_path))
    except OSError:
        pass
    appimage_path = os.environ.get("APPIMAGE")
    frozen = getattr(sys, "frozen", False)
    if frozen and frozen == "macosx_app":  # py2app
        executable = os.path.join(
            os.path.dirname(os.path.realpath(sys.executable)), APP_NAME
        )
    elif appimage_path:
        executable = appimage_path
    elif frozen:
        executable = os.path.realpath(sys.executable)
    else:
        executable = os.path.realpath(sys.argv[0])
    if sys.platform == "win32":
        _autostart_enable_windows(executable)
    elif sys.platform == "darwin":
        _autostart_enable_mac(executable)
    else:
        _autostart_enable_linux(executable)
    logging.debug("Wrote autostart file to '%s'", autostart_file_path)


def autostart_is_enabled():
    return os.path.exists(autostart_file_path)


def autostart_disable():
    logging.debug("Deleting autostart file '%s'...", autostart_file_path)
    os.remove(autostart_file_path)
    logging.debug("Deleted autostart file '%s'", autostart_file_path)