#!/Users/derekjanni/hallmonitor/venv/bin/python3.6

import yaml
import shutil
import argparse
import requests
import functools
import traceback
import logging
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.schedulers.background import BackgroundScheduler
import hallmonitor.addons as addons
from colorama import Fore, Back, Style

logging.basicConfig(level=logging.DEBUG)

# Use globals to inject headers. Follow the example for Auth0 header
global AUTH_HEADER
AUTH_HEADER=None

# Define custom actions up here
def export_auth_header(header):
    global AUTH_HEADER
    AUTH_HEADER=header

ACTION_MAPPING = {
    'auth_header': export_auth_header
}

# Define custom addons here
ADDON_MAPPING = {
    'auth0': addons.auth0_handler
}

def resolve_addon(addon):
    """
    Look I know this is evil but we parse the yaml and do what it says
    to resolve addon functionality. Someday will have a better way
    """
    addon_name = addon['name']
    addon_handler = ADDON_MAPPING[addon_name]
    addon_action = addon['action']
    result = addon_handler(addon)
    action = ACTION_MAPPING[addon_action]
    action(result)


def save_response(filename, content):
    with open(filename, 'wb') as f:
        f.write(content)

def handle_test():
    """
    Decorator for graceful connection handling
    """
    def _decorator(run_function):
        @functools.wraps(run_function)
        def _caller(*args, **kwargs):
            # Print header
            print(f'{Fore.WHITE}=' * shutil.get_terminal_size().columns)

            # Print test description
            print(f'{Fore.YELLOW}{kwargs.get("description")}')

            # Reset style
            print(Style.RESET_ALL)

            try:
                res = run_function(*args, **kwargs)
                if res.status_code == 200:
                    print(f'{Fore.BLUE}{res}')

                    if kwargs.get('json'):
                        print(f'{Fore.BLUE}{res.json()}')

                    if kwargs.get('outfile'):
                        save_response(kwargs.get('outfile'), res.content)
                else:
                    print(f'{Fore.RED}{res}')
                    print(f'{Fore.RED}{res.json()}')

                print(Style.RESET_ALL)
            except:
                print(f'{Fore.RED}')
                traceback.print_exc()
                print(Style.RESET_ALL)

        return _caller
    return _decorator


@handle_test()
def test_case(**kwargs):
    return requests.get(f'{kwargs["base"]}{kwargs["route"]}', params=kwargs.get('params'), headers=AUTH_HEADER)

def main(config=None, cli=True, **kwargs):
    print(f'config {config}')
    print(f'cli {cli}')
    print(f'kwargs {kwargs}')
    if cli is True:
        # Load optional arguments if using cli. Otherwise pass args from main
        parser = argparse.ArgumentParser()
        parser.add_argument("--path", "-p", default='', help="Path to config file")
        parser.add_argument("--file", "-f", help="Name of config file", required=True)
        parser.add_argument("--monitor", "-m", help="Turns on monitoring", action='store_true')
        parser.add_argument("--schedule", "-s", help="Minute schedule to run this on", type=float, default=0.1)
        args = parser.parse_args()
        filename = args.file
        path = args.path
        monitor = args.monitor
        schedule = args.schedule
        scheduler = BlockingScheduler()
    else:
        monitor = kwargs.get('monitor')
        schedule = kwargs.get('schedule', 0.1)
        scheduler = BackgroundScheduler()

    if not config:
        with open(f'{path}{filename}') as stream:
            config = yaml.safe_load(stream)

    addons = config.get('addons', [])
    for addon in addons:
        resolve_addon(addon)

    test_cases = config.get('test_cases', [])
    for test in test_cases:
        test_case(**test)

    if monitor:
        for test in test_cases:
            job = scheduler.add_job(test_case, 'interval', kwargs=test, minutes=schedule)

        scheduler.start()

if __name__ == '__main__':
    main()
