#!/usr/bin/env python3
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) KALEIDOS INC

import argparse
import json
import socket
import sys

from getpass import getpass
from urllib.parse import urlparse

PREPL_URI = "tcp://localhost:6063"

def get_prepl_conninfo():
    uri_data = urlparse(PREPL_URI)
    if uri_data.scheme != "tcp":
        raise RuntimeError(f"invalid PREPL_URI: {PREPL_URI}")

    if not isinstance(uri_data.netloc, str):
        raise RuntimeError(f"invalid PREPL_URI: {PREPL_URI}")

    host, port = uri_data.netloc.split(":", 2)

    if port is None:
        port = 6063

    if isinstance(port, str):
        port = int(port)

    return host, port

def send_eval(expr):
    host, port = get_prepl_conninfo()

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        s.send(expr.encode("utf-8"))
        s.send(b":repl/quit\n\n")

        with s.makefile() as f:
            result = json.load(f)
            tag = result.get("tag", None)
            if tag != "ret":
                raise RuntimeError("unexpected response from PREPL")
            return result.get("val", None), result.get("exception", None)

def encode(val):
    return json.dumps(json.dumps(val))

def print_error(res):
    for error in res["via"]:
        print("ERR:", error["message"])
        break

def run_cmd(params):
    expr = "(app.srepl.ext/run-json-cmd {})".format(encode(params))
    res, failed = send_eval(expr)
    if failed:
        print_error(res)
        sys.exit(-1)

    return res

def create_profile(fullname, email, password):
    params = {
        "cmd": "create-profile",
        "params": {
            "fullname": fullname,
            "email": email,
            "password": password
        }
    }

    res = run_cmd(params)
    print(f"Created: {res['email']} / {res['id']}")

def update_profile(email, fullname, password, is_active):
    params = {
        "cmd": "update-profile",
        "params": {
            "email": email,
            "fullname": fullname,
            "password": password,
            "is_active": is_active
        }
    }

    res = run_cmd(params)
    if res is True:
        print(f"Updated")
    else:
        print(f"No profile found with email {email}")

def derive_password(password):
    params = {
        "cmd": "derive-password",
        "params": {
            "password": password,
        }
    }

    res = run_cmd(params)
    print(f"Derived password: \"{res}\"")

available_commands = [
    "create-profile",
    "update-profile",
    "derive-password"
]

parser = argparse.ArgumentParser(
    description=(
        "Penpot Command Line Interface (CLI)"
    )
)

parser.add_argument("-V", "--version", action="version", version="Penpot CLI %%develop%%")
parser.add_argument("action", action="store", choices=available_commands)
parser.add_argument("-n", "--fullname", help="Fullname", action="store")
parser.add_argument("-e", "--email", help="Email", action="store")
parser.add_argument("-p", "--password", help="Password", action="store")
parser.add_argument("-c", "--connect", help="Connect to PREPL", action="store", default="tcp://localhost:6063")

args = parser.parse_args()

PREPL_URI = args.connect

if args.action == "create-profile":
    email = args.email
    password = args.password
    fullname = args.fullname

    if email is None:
        email = input("Email: ")

    if fullname is None:
        fullname = input("Fullname: ")

    if password is None:
        password = getpass("Password: ")

    create_profile(fullname, email, password)

elif args.action == "update-profile":
    email = args.email
    password = args.password

    if email is None:
        email = input("Email: ")

    if password is None:
        password = getpass("Password: ")

    update_profile(email, None, password, None)

elif args.action == "derive-password":
    password = args.password

    if password is None:
        password = getpass("Password: ")

    derive_password(password)