import os
from sys import stdout
from getpass import getpass
import re
import json
import logging
import socket
from urllib.error import HTTPError

from ..cli import Application
from ..errors import UserError
from ..types import T_PASSWORD, T_USERNAME
from ..toolkit.app import define_core_arguments
from ..tools import validate_parameters
from ..httpsclient import https_request
from .agent import list_options_specs


try:
    input = raw_input
except NameError:
    pass

logger = logging.getLogger(__name__)


def ask_password():
    try:
        raw_pass = os.environ['TEMBOARD_UI_PASSWORD']
    except KeyError:
        raw_pass = getpass(" Password: ")

    try:
        password = raw_pass
        validate_parameters({'password': password},
                            [('password', T_PASSWORD, False)])
    except HTTPError:
        stdout.write("Invalid password.\n")
        return ask_password()
    return password


def ask_username():
    try:
        raw_username = os.environ['TEMBOARD_UI_USER']
    except KeyError:
        raw_username = input(" Username: ")

    try:
        username = raw_username
        validate_parameters({'username': username},
                            [('username', T_USERNAME, False)])
    except HTTPError:
        stdout.write("Invalid username.\n")
        return ask_username()
    return username


class RegisterApplication(Application):
    """Register a couple PostgreSQL instance/agent to a temBoard UI."""

    PROGRAM = "temboard-agent-register"

    def main(self, argv, environ):
        parser = self.create_parser(add_help=False)
        self.define_arguments(parser)
        args = parser.parse_args(argv)
        self.bootstrap(args=args, environ=environ)
        return wrapped_main(args, self)

    def define_arguments(self, parser):
        define_core_arguments(parser, appversion=Application.VERSION)

        parser.add_argument(
            '-?', '--help',
            action='help',
            help='show this help message and exit')

        parser.add_argument(
            '-h', '--host',
            dest='host',
            help="Agent address. Default: %(default)s",
            default=socket.getfqdn(),
        )
        self.config_specs['temboard_port'].add_argument(
            parser, '-p', '--port',
            help="Agent listening TCP port. Default: %(default)s",
        )

        parser.add_argument(
            '-g', '--groups',
            dest='groups',
            help="Instance groups list, comma separated. Default: %(default)s",
            default=None,
        )
        parser.add_argument(
            'ui_address',
            metavar='TEMBOARD-UI-ADDRESS',
            help="temBoard UI address to register to.",
        )


def wrapped_main(args, app):
    agent_baseurl = "https://{}:{}".format(args.host, app.config.temboard.port)
    discover_url = agent_baseurl + '/discover'

    try:
        # Getting system/instance informations using agent's discovering API
        logger.info(
            "Getting system & PostgreSQL informations from the agent (%s) ...",
            discover_url)
        (code, content, cookies) = https_request(
            None,
            'GET',
            discover_url,
            headers={
                "Content-type": "application/json",
                "X-Temboard-Agent-Key": app.config.temboard['key'],
            },
        )
        infos = json.loads(content.decode("utf-8"))

        logger.info(
            "Agent responded at %s:%s.", args.host, app.config.temboard.port)
        logger.info(
            "For %s instance at %s listening on port %s.",
            infos['pg_version_summary'], infos['pg_data'], infos['pg_port'],
        )

        logger.info("Login at %s ...", args.ui_address)
        username = ask_username()
        password = ask_password()
        (code, content, cookies) = https_request(
            None,
            'POST',
            "%s/json/login" % (args.ui_address.rstrip('/')),
            headers={
                "Content-type": "application/json"
            },
            data={'username': username, 'password': password}
        )
        temboard_cookie = None
        for cookie in cookies.split("\n"):
            cookie_content = cookie.split(";")[0]
            if re.match(r'^temboard=.*$', cookie_content):
                temboard_cookie = cookie_content
                continue

        if args.groups:
            groups = [g for g in args.groups.split(',')]
        else:
            groups = None

        # POSTing new instance
        logger.info("Registering instance/agent to %s ...", args.ui_address)
        (code, content, cookies) = https_request(
            None,
            'POST',
            "%s/json/register/instance" % (args.ui_address.rstrip('/')),
            headers={
                "Content-type": "application/json",
                "Cookie": temboard_cookie
            },
            data={
                'hostname': infos['hostname'],
                'agent_key': app.config.temboard['key'],
                'agent_address': args.host,
                'agent_port': str(app.config.temboard['port']),
                'cpu': infos['cpu'],
                'memory_size': infos['memory_size'],
                'pg_port': infos['pg_port'],
                'pg_data': infos['pg_data'],
                'pg_version': infos['pg_version'],
                'pg_version_summary': infos['pg_version_summary'],
                'plugins': infos['plugins'],
                'groups': groups
            }
        )
        if code != 200:
            raise HTTPError(code, content)
        logger.info("Done.")
    except UserError:
        raise
    except HTTPError as e:
        msg = json.loads(e.read())['error']
        if e.url.startswith(agent_baseurl):
            msg = "Failed to contact agent: %s. Are you mixing agents ?" % msg
        raise UserError(msg)
    except Exception as e:
        raise UserError(str(e) or repr(e))

    return 0


main = RegisterApplication(specs=list_options_specs(), with_plugins=False)

if __name__ == '__main__':  # pragma: no cover
    main()
