#!/usr/bin/env python3

"""
Behavior:
    A qutebrowser userscript that adds recipes to Nextcloud's Cookbook app.

Requirements:
    requests

userscript setup:
    Optionally create ~/.config/qutebrowser/add-nextcloud-cookbook.ini like:

[nextcloud]
HOST=https://nextcloud.example.com
USER=username
;PASSWORD=lamepassword

    If settings aren't in the configuration file, the user will be prompted.
    If the user does not want to be prompted for a password, it is recommended
    to set up an 'app password' with 'Allow filesystem access' enabled.
    See the following for instructions:
    https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html#managing-devices  # noqa: E501

qutebrowser setup:
    add recipe via hints
        config.bind('X', 'hint links userscript add-nextcloud-cookbook')

    add recipe of current URL
        config.bind('X', 'spawn --userscript add-nextcloud-cookbook')

troubleshooting:
    Errors detected within this userscript will have an exit of 231.  All other
    exit codes will come from requests.
"""

import configparser
from os import environ, path
from sys import argv, exit

from PyQt6.QtWidgets import QApplication, QInputDialog, QLineEdit
from requests import post
from requests.auth import HTTPBasicAuth


def get_text(name, info):
    """Get input from the user."""
    _app = QApplication(argv)  # noqa: F841
    if name == "password":
        text, ok = QInputDialog.getText(
            None,
            "add-nextcloud-cookbook userscript",
            "Please enter {}".format(info),
            QLineEdit.EchoMode.Password,
        )
    else:
        text, ok = QInputDialog.getText(
            None, "add-nextcloud-cookbook userscript", "Please enter {}".format(info)
        )
    if not ok:
        message("info", "Dialog box canceled.")
        exit(0)
    return text


def message(level, text):
    """display message"""
    with open(environ["QUTE_FIFO"], "w") as fifo:
        fifo.write(
            "message-{} 'add-nextcloud-cookbook userscript: {}'\n".format(level, text)
        )
        fifo.flush()


if "QUTE_FIFO" not in environ:
    print(
        "This script is designed to run as a qutebrowser userscript, "
        "not as a standalone script."
    )
    exit(231)

if "QUTE_CONFIG_DIR" not in environ:
    if "XDG_CONFIG_HOME" in environ:
        QUTE_CONFIG_DIR = environ["XDG_CONFIG_HOME"] + "/qutebrowser"
    else:
        QUTE_CONFIG_DIR = environ["HOME"] + "/.config/qutebrowser"
else:
    QUTE_CONFIG_DIR = environ["QUTE_CONFIG_DIR"]

config_file = QUTE_CONFIG_DIR + "/add-nextcloud-cookbook.ini"
if path.isfile(config_file):
    config = configparser.ConfigParser()
    config.read(config_file)
    settings = dict(config.items("nextcloud"))
else:
    settings = {}

settings_info = [
    ("host", "host information.", "required"),
    ("user", "username.", "required"),
    ("password", "password.", "required"),
]

# check for settings that need user interaction
for setting in settings_info:
    if setting[0] not in settings:
        userInput = get_text(setting[0], setting[1])
        settings[setting[0]] = userInput

api_url = settings["host"] + "/index.php/apps/cookbook/import"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
auth = HTTPBasicAuth(settings["user"], settings["password"])
data = "url=" + environ["QUTE_URL"]

message("info", "starting to process {}".format(environ["QUTE_URL"]))

r = post(api_url, data=data, headers=headers, auth=auth, timeout=(3.05, 27))

if r.status_code == 200:
    message("info", "recipe from {} added.".format(environ["QUTE_URL"]))
    exit(0)
elif r.status_code == 500:
    message("warning", "Cookbook app reports {}".format(r.text))
    exit(0)
else:
    message(
        "error",
        "Could not connect to {} with status code {}".format(
            settings["host"], r.status_code
        ),
    )
    exit(r.status_code)
