#!python
# -*- coding: utf-8 -*-
"""
auton-client
"""

__license__ = """
    Copyright (C) 2018  fjord-technologies

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
__version__ = '0.1.26'

import logging
import os
import requests
import sys
import time

from dotenv.main import dotenv_values
from optparse import OptionParser
from sonicprobe.libs import urisup

SYSLOG_NAME   = "auton-client"
LOG           = logging.getLogger(SYSLOG_NAME)
DEFAULT_DELAY = 0.5


def argv_parse_check():
    """
    Parse (and check a little) command line parameters
    """
    parser           = OptionParser(usage="usage: %prog [options]")

    parser.add_option("-l",
                      dest      = 'loglevel',
                      default   = 'info',   # warning: see affectation under
                      choices   = ('critical', 'error', 'warning', 'info', 'debug'),
                      help      = ("Emit traces with LOGLEVEL details, must be one of:\t"
                                   "critical, error, warning, info, debug"))
    parser.add_option("--uri",
                      dest      = 'uri',
                      default   = os.environ.get('AUTON_URI'),
                      help      = "Auton URI address")
    parser.add_option("--uid",
                      dest      = 'uid',
                      default   = os.environ.get('AUTON_UID'),
                      help      = "Auton uid")
    parser.add_option("--endpoint",
                      dest      = 'endpoint',
                      default   = os.environ.get('AUTON_ENDPOINT'),
                      help      = "Auton endpoint")
    parser.add_option("--auth-user",
                      dest      = 'auth_user',
                      default   = os.environ.get('AUTON_AUTH_USER'),
                      help      = "Auton auth user")
    parser.add_option("--auth-passwd",
                      dest      = 'auth_passwd',
                      default   = os.environ.get('AUTON_AUTH_PASSWD'),
                      help      = "Auton auth password")
    parser.add_option("--delay",
                      dest      = 'delay',
                      type      = 'float',
                      default   = DEFAULT_DELAY,
                      help      = "Delay between requests instead of %default")
    parser.add_option("--mode",
                      dest      = 'mode',
                      default   = 'autorun',
                      choices   = ('autorun', 'run', 'status'),
                      help      = "Auton mode: autorun, run, status")
    parser.add_option("-e",
                      action    = 'append',
                      dest      = 'envvars',
                      default   = [],
                      help      = "Passed environment variables")
    parser.add_option("--envfile",
                      action    = 'append',
                      dest      = 'envfiles',
                      default   = [],
                      help      = "Passed envfile parameters")
    parser.add_option("--load-envfile",
                      action    = 'append',
                      dest      = 'load_envfiles',
                      default   = [],
                      help      = "Load environment variables from file")
    parser.add_option("-a",
                      action    = 'append',
                      dest      = 'args',
                      default   = [],
                      help      = "Passed arguments")

    options, args    = parser.parse_args()

    if args:
        parser.error("no argument is allowed - use option --help to get an help screen")

    options.loglevel = getattr(logging, options.loglevel.upper(), logging.INFO)

    return options

class AutonClient(object):
    def __init__(self, options):
        self.options = options
        self.envvars = {}

        if not self.options.uri:
            raise ValueError("missing variable AUTON_URI")

        if not self.options.uid:
            raise ValueError("missing variable AUTON_UID")

        if not self.options.endpoint:
            raise ValueError("missing variable AUTON_ENDPOINT")

        self._load_envfiles()
        self._parse_envvars()
        self._auth = None
        if self.options.auth_user:
            self._auth = (self.options.auth_user,
                          self.options.auth_passwd or '')

    def _load_envfiles(self):
        for envfile in self.options.load_envfiles:
            self.envvars.update(dotenv_values(envfile))

    def _parse_envvars(self):
        for envvar in self.options.envvars:
            env = envvar.split('=', 1)
            if not env[0]:
                LOG.warning("invalid environment variable: %r", env)
            elif len(env) == 1:
                self.envvars[env[0]] = ''
            else:
                self.envvars[env[0]] = env[1]

    def _build_uri(self, method):
        r    = list(urisup.uri_help_split(self.options.uri))
        r[2] = "/%s/%s/%s" % (method, self.options.endpoint, self.options.uid)

        return urisup.uri_help_unsplit(r)

    def _check_results(self, res = None):
        if not res:
            raise LookupError("unknown error")
        elif res.get('message'):
            raise LookupError("invalid request, message: %s" % res['message'])
        elif res.get('code'):
            return res
        else:
            raise LookupError("errors occurred: %r" % res)

    def do_run(self):
        req = None

        try:
            req  = requests.post(self._build_uri('run'),
                                 auth = self._auth,
                                 json = {'args':     self.options.args,
                                         'env':      self.envvars,
                                         'envfiles': self.options.envfiles})

            if not req.text:
                return self._check_results()
            return self._check_results(req.json())
        finally:
            if req:
                req.close()

    def do_status(self):
        req = None

        try:
            req = requests.get(self._build_uri('status'),
                               auth = self._auth)

            if not req.text:
                return self._check_results()
            return self._check_results(req.json())
        finally:
            if req:
                req.close()

    def _show_results(self, data):
        if data.get('stream'):
            for x in data['stream']:
                print x

        if data['status'] == 'complete' \
           and data.get('errors'):
            for x in data['errors']:
                LOG.error(x)

    def do_autorun(self):
        data = self.do_run()
        while data['status'] != 'complete':
            time.sleep(self.options.delay)
            data = self.do_status()
            self._show_results(data)

        return int(data['code'] != 200)


def main(options):
    """
    Main function
    """

    xformat = "%(levelname)s:%(asctime)-15s: %(message)s"
    datefmt = '%Y-%m-%d %H:%M:%S'
    logging.basicConfig(level   = options.loglevel,
                        format  = xformat,
                        datefmt = datefmt)

    auton   = None
    rc      = 0

    try:
        auton = AutonClient(options)
        rc    = getattr(auton, "do_%s" % options.mode)()
    except (KeyboardInterrupt, SystemExit):
        rc = 2
    except Exception, e:
        LOG.error(e)
        rc = 1
        raise
    finally:
        sys.exit(rc)


if __name__ == '__main__':
    main(argv_parse_check())
