#!/usr/bin/env python3
# Dependent packages:
import json
import logging as log
import os
import requests
import yaml
import sys

from restdriver import cli


__author__ = 'kgraham'
__version__ = '0.0.0-0'


def init_defaults():
    cwd = os.getcwd()
    root = os.path.abspath('/')
    defaults = dict(config_file=os.path.join(cwd, 'environments.yaml'),
                    suite_file=os.path.join(cwd, 'suites', 'default.tcs'),
                    results_file=os.path.join(cwd, 'results', 'default.rslt'),
                    log_file=os.path.join(root, 'var', 'log', 'restdriver', 'restdriver.log'))
    return defaults


def load_config_file(config):
    # Load Config
    try:
        with open(config['config_file'], 'r') as yamlfile:
            yamlconfig = yaml.load(yamlfile)
            config.update(yamlconfig)
    except FileNotFoundError:
        log.error("Error: Config file %s not found" % config['config_file'])
        sys.exit(1)
    except yaml.YAMLError as err:
        if hasattr(err, 'problem_mark'):
            mark = err.problem_mark
            log.error("Error: Invalid config file %s" % config['config_file'])
            log.error("Error: Location (%s line %d)" % (config['config_filename'], mark.line+1))
        else:
            log.error("Error: ", err)
        sys.exit(1)

    # Log the configuration
    log.info('------------------------------------------')
    log.info("  Config file   : %s" % config['config_file'])
    log.info("  Log file      : %s" % config['log_file'])
    log.info("  Results file  : %s" % config['results_file'])
    log.info("  Test suite    : %s" % config['suite_file'])
    log.debug("  Configuration : %s" % config)
    log.info('------------------------------------------')

    return config


def initialize():
    defaults = init_defaults()
    parser = cli.get_parser(defaults)
    options, args = parser.parse_args()

    # Setup log
    log_level = getattr(log, options.debug_level.upper())
    debug_enabled = (log_level == log.DEBUG)

    try:
        log.basicConfig(format='%(asctime)s %(levelname)-5s [(%(thread)s) %(module)s:%(lineno)s] %(message)s',
                        filemode='w', level=log_level, filename=options.log_file)
        log.getLogger().addHandler(log.StreamHandler())
        log.info('------------------------------------------')
        log.info('Starting %s' % __file__)
    except (FileNotFoundError, IOError) as err:
        print("Failed to open log file '%s', check permissions" % options.log_file, file=sys.stderr)
        print(err, file=sys.stderr)
        sys.exit(1)

    # Normalize file names to absolute paths
    config_dir, config_filename, config_file = normalize_filename(options.config_file)
    log_dir, log_filename, log_file = normalize_filename(options.log_file)
    results_dir, results_filename, results_file = normalize_filename(options.results_file)
    suite_dir, suite_filename, suite_file = normalize_filename(options.suite_file)

    # Save initial configuration
    config = dict(config_file=config_file, config_filepath=config_dir, config_filename=config_filename,
                  log_file=log_file, log_filepath=log_dir, log_filename=log_filename,
                  results_file=results_file, results_filepath=results_dir, results_filename=results_filename,
                  suite_file=suite_file, suite_filepath=suite_dir, suite_filename=suite_filename,
                  log_level=log_level, debug_enabled=debug_enabled)

    # Add configuration from config file
    config = load_config_file(config)

    return config


def normalize_filename(file_path):
    file_dir, file_name = os.path.split(file_path)
    file_dir = os.path.abspath(file_dir)
    absolute_filename = os.path.join(file_dir, file_name)
    return file_dir, file_name, absolute_filename


def load_suite_templates(suite, config):
    message_templates = {}
    if 'message_t' in suite:
        message_templates = suite['message_t']

    return message_templates


def load_suite_testcases(suite, config):
    testcases = {}
    if 'testcase' in suite:
        testcases = suite['testcase']

    return testcases


def load_suite(suite_file, config):
    try:
        with open(suite_file, 'r') as yamlfile:
            suite = yaml.load(yamlfile)
            message_templates = load_suite_templates(suite, config)
            log.debug("Message Templates:\n%s" % json.dumps(message_templates, indent=2))
            testcases = load_suite_testcases(suite, config)
            log.debug("Test Cases:\n%s" % json.dumps(testcases, indent=2))
    except FileNotFoundError:
        log.error("Error: Config file %s not found" % config['config_file'])
        sys.exit(1)
    except yaml.YAMLError as err:
        if hasattr(err, 'problem_mark'):
            mark = err.problem_mark
            log.error("Error: Invalid config file %s" % config['config_file'])
            log.error("Error: Location (%s line %d)" % (config['config_filename'], mark.line+1))
        else:
            log.error("Error: ", err)
        sys.exit(1)

    return message_templates, testcases


def run_command(command):
    for cmd_name, cmd_data in command.items():
        print('%s' % type(cmd_data))
        print('%s' % cmd_data)
        if cmd_name == 'send':
            method = cmd_data['method']
            url = cmd_data['baseurl'] + '/' + cmd_data['resource']
            if method.upper() == "GET":
                response = requests.get(url)
                headers = ""
                for key, val in response.headers.items():
                    headers += "%s: %s\n" % (key, val)
#                if response.headers['Content-Type'] == 'application/json':
                content_string = json.dumps(response.json(), indent=2)
                print("RESPONSE %s %s\n%s\n%s" % (response.status_code, response.reason, headers, content_string))
        break


def run_testcase(testcase, message_templates):
    for tc_name, tc_data in testcase.items():
        print("1>>> %s" % tc_name)
        print("1>>> %s" % tc_data)
        for cmd in tc_data:
            run_command(cmd)


def run_suite(config):
    message_templates, testcases = load_suite(config['suite_file'], config)
    for testcase in testcases:
        print("2>>> %s" % testcase)
        run_testcase(testcase, message_templates)


def main():
    config = initialize()
    run_suite(config)


if __name__ == '__main__':
    main()
