"""
Authenticate a user
"""
from __future__ import unicode_literals
import json
import getpass
from os.path import join
import logging
import platform
import sys
import requests
from six.moves import input
from urllib.parse import urlparse
import webbrowser

from ..utils.config import (
    store_token, get_config, DEFAULT_URL, OIDC_CLIENT_ID, OIDC_CONFIGURATION_PATH
)
from .. import errors
from ..utils.api import RepoApi
from ..utils.local_auth_server import WebServer
from .base import SubCommandBase

logger = logging.getLogger('repo_cli')


def get_login_and_password(args):
    if getattr(args, 'login_username', None):
        username = args.login_username
    else:
        username = input('Username: ')
    #
    password = getattr(args, 'login_password', None)
    return username, password


def interactive_get_token(args, fail_if_already_exists=True):
    # bs = get_server_api(args.token, args.site)
    config = get_config(site=args.site)

    token = None
    # This function could be called from a totally different CLI, so we don't
    # know if the attribute hostname exists.
    # args.site or config.get('default_site')
    url = config.get('url', DEFAULT_URL)
    username, password = get_login_and_password(args)

    for _ in range(3):
        try:
            if password is None:
                password = getpass.getpass(stream=sys.stderr)

            api = RepoApi(base_url=url)
            token = api.login(username, password)

            # token = login_user(username, password, url)
            if not token:
                msg = 'Unable to request the user token. Server was unable to return any valid token!'
                logger.error(msg)
                raise errors.RepoCLIError(msg)
            return token['user']

        except errors.Unauthorized:
            logger.error('Invalid Username password combination, please try again')
            password = None
            continue

    return token['user']


def interactive_login(args):
    token = interactive_get_token(args)
    store_token(token, args)
    logger.info('login successful')
    return token


def main(args):
    interactive_login(args)


class SubCommand(SubCommandBase):
    name = "login"
    manages_auth = True

    def main(self):
        self.login()

    def login(self):
        token = self.interactive_get_token()
        store_token(token, self.args)
        is_admin = self.api.is_admin_jwt
        msg = 'login as ADMIN successful' if is_admin else 'login successful'
        self.log.info(msg)
        return token  # ['id']

    def get_login_and_password(self):
        if getattr(self.args, 'login_username', None):
            username = self.args.login_username
        else:
            username = input('Username: ')
        self.username = username
        password = getattr(self.args, 'login_password', None)
        return username, password

    def interactive_get_token(self):
        config = get_config()
        if config.get('oauth2'):
            token = self.oauth2_get_token()
        else:
            token = self.direct_get_token()
        return token

    def get_and_validate_user_token(self):
        user_token = self.api.get_user_token()

        if not user_token:
            msg = 'Unable to request the user token. Server was unable to return any valid user token!'
            logger.error(msg)
            raise errors.RepoCLIError(msg)

        return user_token

    def direct_get_token(self):
        username, password = self.get_login_and_password()
        for _ in range(3):
            try:
                if password is None:
                    password = getpass.getpass(stream=sys.stderr)

                jwt_token = self.api.login(username, password)
                user_token = self.get_and_validate_user_token()
                return user_token

            except errors.Unauthorized:
                logger.error('Invalid Username password combination, please try again')
                password = None
                continue

        raise errors.RepoCLIError("You've reached maximum login attempts")

    def get_openid_configuration_url(self):
        url = urlparse(self.api.base_url)
        return url._replace(path=OIDC_CONFIGURATION_PATH).geturl()

    def oauth2_get_token(self):
        server = WebServer(
            client_id=OIDC_CLIENT_ID,
            openid_configuration_url=self.get_openid_configuration_url()
        )
        thread = server.start()
        thread.start()
        self.log.info("Opening browser to get a token...")
        webbrowser.open(server.localhost_url())
        thread.join(120)
        if not server.access_token:
            msg = 'Unable to request the user token. Server was unable to return any valid token!'
            logger.error(msg)
            raise errors.RepoCLIError(msg)
        self.api._jwt = server.access_token
        user_token = self.get_and_validate_user_token()
        return user_token

    def add_parser(self, subparsers):
        self.subparser = subparser = subparsers.add_parser('login', help='Authenticate a user', description=__doc__)
        subparser.add_argument('--hostname', default=platform.node(),
                               help="Specify the host name of this login, this should be unique (default: %(default)s)")
        subparser.add_argument('--username', dest='login_username',
                               help="Specify your username. If this is not given, you will be prompted")
        subparser.add_argument('--password', dest='login_password',
                               help="Specify your password. If this is not given, you will be prompted")
        subparser.set_defaults(main=self.main)