"""
Interactive CLI client for browsing, managing, and editing tasks on a Nextcloud instance.
"""

from typing import Optional

import sys
import argparse
from subprocess import run, SubprocessError
from tempfile import NamedTemporaryFile

from nextcloud_tasks_api import NextcloudTasksApi, get_nextcloud_tasks_api
from .config import Config, ConfigError
from .prompts import print_err, prompt_password
from .api import TasksApi
from .cli import cli_main


def _decrypt(encrypted: str, password: str) -> Optional[str]:
    with NamedTemporaryFile("w", delete=True) as pass_file:
        pass_file.write(password)  # don't expose password in subprocess arguments
        pass_file.flush()
        try:
            # echo -n "nextcloud-password" | openssl enc -e -aes-256-cbc -salt -pbkdf2 -base64
            proc = run(["openssl", "enc", "-d",
                        "-aes-256-cbc", "-salt", "-pbkdf2", "-base64",
                        "-pass", f"file:{pass_file.name}"],
                       input=f"{encrypted}\n",
                       capture_output=True,
                       encoding="utf-8", errors="strict",
                       check=True)
        except (SubprocessError, UnicodeError) as e:
            print_err(f"Cannot decrypt password: {str(e)}")
            return None
        else:
            return proc.stdout


def _get_password(config: Config) -> Optional[str]:
    if config.password_type == "openssl-aes":
        passphrase: Optional[str] = prompt_password()
        if passphrase is None:
            print_err("Cannot decrypt password: No passphrase given")
            return None
        return _decrypt(config.password, passphrase)
    else:
        return config.password


def _main(config: Config) -> bool:
    password: Optional[str] = _get_password(config)
    if password is None:
        return False
    api: NextcloudTasksApi = get_nextcloud_tasks_api(base_url=config.base_url,
                                                     username=config.username, password=password,
                                                     verify_ssl=config.verify_ssl,
                                                     stream=True)
    return cli_main(TasksApi(api))


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__.strip(),
                                     formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('-c', type=str, metavar="CONFIG", default="./tasks_config.ini",
                        help="configuration file, in .ini or .json format")
    args = parser.parse_args()

    try:
        config: Config = Config.from_file(args.c)
    except ConfigError as e:
        print_err(f"Cannot load config from '{args.c}': {str(e)}")
        return 1
    else:
        return 0 if _main(config) else 1


if __name__ == "__main__":
    sys.exit(main())