#!/usr/bin/env python
# coding: utf-8

from __future__ import print_function
from __future__ import unicode_literals

import logging
import json
import sys
import os
import time
from getpass import getpass

import requests
from requests.auth import HTTPBasicAuth
from prettytable import PrettyTable, PLAIN_COLUMNS
from six.moves import input
import pkg_resources

import client.launcher as launcher
import lib.utils as utils
import lib.opts as opts
import lib.credentials as credentials
from lib.commands.user import User
from lib.commands.permission import list_permission
from lib.commands.entity import Entity
from lib.commands.group import Group
from lib.commands.role import Role
from lib.commands.resource import Resource
from lib.commands.docker import Docker
from lib.commands.model import Model
from lib.commands.vocab import Vocab
from lib.commands.task import Task
from lib.commands.share import Share
from lib.commands.tag import Tag
from lib.commands.service import Service

if os.environ.get("SNW_URL") is None:
    os.environ["SNW_URL"] = "https://api-snw.systran.net"

if os.environ.get("LAUNCHER_URL") is None:
    os.environ["LAUNCHER_URL"] = "https://api-snw.systran.net"

launcher.append_version(pkg_resources.require("snw")[0].version)

opts.define_option()

launcher.argparse_preprocess()
args = launcher.parser.parse_args()

logging.basicConfig(stream=sys.stderr, level=args.log_level)
launcher.LOGGER = logging.getLogger()

requests_log = logging.getLogger("requests.packages.urllib3")
if args.log_level == "DEBUG":
    requests_log.setLevel(logging.DEBUG)
    launcher.HTTPConnection.debuglevel = 1
else:
    requests_log.setLevel(logging.WARNING)
requests_log.propagate = True

if args.url is None:
    args.url = os.getenv('SNW_URL')
    if args.url is None:
        launcher.LOGGER.error('missing launcher_url')
        sys.exit(1)

if "subcmd" not in args:
    args.subcmd = None

token, current_account = credentials.get_credential(args.url, args.subcmd == 'login' and args.user)

if args.cmd == 'auth' and args.subcmd == 'login':
    if args.user:
        current_account = args.user
    if current_account:
        launcher.LOGGER.info("login as %s", current_account)
        login = current_account
    else:
        login = input('Trainer ID: ')
    if token:
        result, r_servicelist = utils.get_services(url=args.url,
                                                   user_auth=HTTPBasicAuth(token, 'x'))
        if not result:
            token = None
        else:
            credentials.activate_credential(args.url, login)
            launcher.LOGGER.info("logged in as %s", login)
            sys.exit(0)
    if not token:
        password = getpass()
        r = requests.get(os.path.join(args.url, "auth/token"),
                         auth=HTTPBasicAuth(login, password))
        if r.status_code != 200:
            launcher.LOGGER.error('invalid credentials')
            sys.exit(1)
        token = str(r.json()['token'])
        duration = r.json()['duration']
        credentials.set_credential(args.url, login, token, duration, time.time())
        launcher.LOGGER.info("logged in as %s", login)
        sys.exit(0)

elif args.cmd == 'auth' and (args.subcmd == 'logout' or args.subcmd == 'revoke'):
    if not token:
        launcher.LOGGER.error('No connection token')
        sys.exit(1)
    credentials.remove_credential(args.url, current_account)
    r = requests.get(os.path.join(args.url, "auth/revoke"),
                     auth=HTTPBasicAuth(token, 'x'),
                     params={'token': token})
    if r.status_code != 200:
        launcher.LOGGER.error('error: %s', r.text)
        sys.exit(1)
    launcher.LOGGER.info("Removed connection token")
    sys.exit(0)

if token is not None:
    auth = HTTPBasicAuth(token, 'x')
else:
    launcher.LOGGER.error('missing authentication token - do login')
    sys.exit(1)

if args.cmd == 'auth' and args.subcmd == 'token':
    status, user_id = utils.get_user(args.url, auth, args.user)
    if not status:
        raise RuntimeError(user_id)
    params = {
        'user_id': user_id,
        'duration': args.duration,
        'persistent': args.persistent
    }
    r = requests.get(os.path.join(args.url, "auth/token"), auth=auth, params=params)
    if r.status_code != 200:
        launcher.LOGGER.error('error: %s', r.text)
        sys.exit(1)
    token = str(r.json()['token'])
    duration = r.json()['duration']
    launcher.LOGGER.info('Got token (%s) for %ss', token, duration)
    sys.exit(0)

if hasattr(args, 'trainer_id') and not args.trainer_id:
    args.trainer_id = ''

try:
    res = None
    if args.cmd == 'service':
        service = Service(args, auth)
        res = service.execute_command()

    elif args.cmd == 'user':
        user = User(args, auth)
        res = user.execute_command()

    elif args.cmd == 'docker':
        docker = Docker(args, auth)
        res = docker.execute_command()

    elif args.cmd == 'permission':
        res = list_permission(args, auth)

    elif args.cmd == 'group':
        group = Group(args, auth)
        res = group.execute_command()

    elif args.cmd == 'role':
        role = Role(args, auth)
        res = role.execute_command()

    elif args.cmd == 'share':
        share = Share(args, auth)
        res = share.execute_command()

    elif args.cmd == 'entity':
        entity = Entity(args, auth)
        res = entity.execute_command()

    elif args.cmd == 'resource':
        resource = Resource(args, auth)
        res = resource.execute_command()

    elif args.cmd == 'model':
        model = Model(args, auth)
        res = model.execute_command()

    elif args.cmd == 'vocab':
        vocab = Vocab(args, auth)
        res = vocab.execute_command()

    elif args.cmd == 'task':
        task = Task(args, auth)
        res = task.execute_command()

    elif args.cmd == 'tag':
        tag = Tag(args, auth)
        res = tag.execute_command()

    elif args.cmd == 'monitoring':
        r = requests.get(os.path.join(args.url, "monitoring"), auth=auth)
        if r.status_code != 200:
            raise RuntimeError('incorrect result from \'monitoring\': %s' % r.text)
        res = r.json()

    if res is None:
        skip_launch = False
        if args.cmd == 'task' and args.subcmd == 'launch':
            task = Task(args, auth)
            task.execute_command()
        if not skip_launch:
            status, serviceList = utils.get_services(url=args.url, user_auth=auth)
            res = launcher.process_request(serviceList, args.cmd, args.subcmd,
                                           args.display == "JSON", args, auth=auth)
except RuntimeError as err:
    launcher.LOGGER.error(str(err))
    sys.exit(1)
except ValueError as err:
    launcher.LOGGER.error(str(err))
    sys.exit(1)

if not isinstance(res, list):
    res = [res]
for r in res:
    if args.display == "JSON" or isinstance(r, dict):
        print(json.dumps(r, indent=2))
    else:
        if isinstance(r, PrettyTable):
            if args.display == "TABLE":
                print(r)
            elif args.display == "RAW":
                r.set_style(PLAIN_COLUMNS)
                print(r)
            else:
                print(r.get_html_string())
        else:
            utils.write_to_stdout(r)
            if not (args.cmd == "task" and args.subcmd == "file") and \
                    not (args.cmd == "task" and args.subcmd == "log") and \
                    not r.endswith("\n"):
                sys.stdout.write("\n")
            sys.stdout.flush()
