#!/usr/bin/env python

import os
import sys

import radicale.__main__

from etesync_dav.config import CONFIG_DIR, RADICALE_CONFIG, RADICALE_CONFIG_FILE


def manage(args):
    import argparse
    import getpass
    import random
    import string

    import etesync as api
    from radicale_storage_etesync.creds import Credentials

    from etesync_dav.config import CREDS_FILE, HTPASSWD_FILE, ETESYNC_URL

    class Htpasswd:
        def __init__(self, filename):
            self.filename = filename
            self.load()

        def load(self):
            if os.path.exists(self.filename):
                with open(self.filename, "r") as f:
                    self.content = dict(map(lambda x: x.strip(), line.split(':', 1)) for line in f)
            else:
                self.content = {}

        def save(self):
            with open(self.filename, "w") as f:
                for name, password in self.content.items():
                    print("{}:{}".format(name, password), file=f)

        def get(self, username):
            return self.content.get(username, None)

        def set(self, username, password):
            self.content[username] = password

        def delete(self, username):
            self.content.pop(username, None)

        def list(self):
            for item in self.content.keys():
                yield item

    def validate_username(htpasswd, username):
        if username is None:
            raise RuntimeError("Username is required")
        if ':' in username:
            raise RuntimeError("Username can't include a colon.")
        return htpasswd.get(username) is not None

    def generate_pasword():
        return ''.join(
                [random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for i in range(16)])

    def print_credentials(htpasswd, username):
        print("User: {}\nPassword: {}".format(args.username, htpasswd.get(args.username)))

    parser = argparse.ArgumentParser()
    parser.add_argument("command",
                        choices=('add', 'del', 'get', 'list'),
                        help="Either add to add a user, del to remove a user, get to show login creds, " +
                             "or list to list all users.")
    parser.add_argument("username",
                        nargs='?',
                        help="The username used with EteSync")
    parser.add_argument("--login-password",
                        help="The password to login to the EteSync server.")
    parser.add_argument("--encryption-password",
                        help="The encryption password")
    args = parser.parse_args(args=args)

    if not os.path.exists(CONFIG_DIR):
        os.makedirs(CONFIG_DIR)

    htpasswd = Htpasswd(HTPASSWD_FILE)
    creds = Credentials(CREDS_FILE)

    remote_url = ETESYNC_URL

    if args.command == 'add':
        exists = validate_username(htpasswd, args.username)
        if exists:
            raise RuntimeError("User already exists. Delete first if you'd like to override settings.")

        login_password = (getattr(args, 'login_password') or
                          getpass.getpass(prompt="Please enter the EteSync login password: "))
        encryption_password = (getattr(args, 'encryption_password') or
                               getpass.getpass(prompt="Please enter your encryption password: "))

        print("Fetching auth token")
        auth_token = api.Authenticator(remote_url).get_auth_token(args.username, login_password)

        print("Deriving password")
        etesync = api.EteSync(args.username, auth_token, remote=remote_url, db_path=':memory:')
        cipher_key = etesync.derive_key(encryption_password)

        print("Saving config")
        generated_password = generate_pasword()
        htpasswd.set(args.username, generated_password)
        creds.set(args.username, auth_token, cipher_key)
        htpasswd.save()
        creds.save()

        print_credentials(htpasswd, args.username)

    elif args.command == 'del':
        exists = validate_username(htpasswd, args.username)
        if not exists:
            raise RuntimeError("User not found")

        print("Deleting user")
        htpasswd.delete(args.username)
        creds.delete(args.username)
        htpasswd.save()
        creds.save()

    elif args.command == 'get':
        exists = validate_username(htpasswd, args.username)
        if not exists:
            raise RuntimeError("User not found")

        print_credentials(htpasswd, args.username)

    elif args.command == 'list':
        for user in htpasswd.list():
            print(user)


if len(sys.argv) > 1 and sys.argv[1] == 'manage':
    manage(sys.argv[2:])
    sys.exit(0)


if len(sys.argv) > 1 and sys.argv[1] == '--version':
    import etesync_dav
    print("EteSync DAV version: ", etesync_dav.__version__)
    print("Radicale version: ", radicale.VERSION)
    sys.exit(0)

if not os.path.exists(CONFIG_DIR):
    print('Configuration not found. Please run "etesync-dav manage" first.')
    sys.exit(1)

if not os.path.exists(RADICALE_CONFIG_FILE):
    with open(RADICALE_CONFIG_FILE, "w") as f:
        f.write(RADICALE_CONFIG)

os.chdir(CONFIG_DIR)
os.environ['RADICALE_CONFIG'] = RADICALE_CONFIG_FILE

radicale.__main__.run()
