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

# system imports
import logging
from os import listdir
from os.path import exists, isfile, isdir, join
from argparse import ArgumentParser
from sys import exit

# project imports
from nrtest.testsuite import TestSuite


def execute(args):
    from nrtest.execute import execute_testsuite, validate_testsuite

    for p in args.tests + [args.app]:
        if not exists(p):
            logging.error('Could not find path: "%s"' % p)

    test_dirs = [p for p in args.tests if isdir(p)]
    test_files = [p for p in args.tests if isfile(p)]
    test_files += [join(d, p) for d in test_dirs for p in listdir(d)
                   if p.endswith('.json')]

    test_files = list(set(test_files))  # remove duplicates

    ts = TestSuite.read_config(args.app, test_files, args.output)

    if not validate_testsuite(ts):
        exit(1)

    try:
        logging.info('Found %i tests' % len(test_files))
        success = execute_testsuite(ts)
        ts.write_manifest()
    except KeyboardInterrupt:
        logging.warning('Process interrupted by user')
        success = False
    else:
        logging.info('Finished')

    # Non-zero exit code indicates failure
    exit(not success)


def compare(args):
    from nrtest.compare import compare_testsuite, validate_testsuite

    ts_new = TestSuite.read_benchmark(args.new)
    ts_old = TestSuite.read_benchmark(args.old)

    if not validate_testsuite(ts_new) or not validate_testsuite(ts_old):
        exit(1)

    try:
        logging.info('Found %i tests' % len(ts_new.tests))
        compatible = compare_testsuite(ts_new, ts_old, args.rtol, args.atol,
                                       args.output)
    except KeyboardInterrupt:
        logging.warning('Process interrupted by user')
        compatible = False
    else:
        logging.info('Finished')

    # Non-zero exit code indicates failure
    exit(not compatible)


if __name__ == '__main__':
    parser = ArgumentParser(description='Numerical regression testing')
    parser.add_argument('-q', '--quiet', help='suppress normal messages',
                        dest='LOGLEVEL', action='store_const',
                        const=logging.WARNING, default=logging.INFO)
    parser.add_argument('-v', '--verbose', help='output debug messages',
                        dest='LOGLEVEL', action='store_const',
                        const=logging.DEBUG, default=logging.INFO)
    subparsers = parser.add_subparsers(title='subcommands')

    e_parser = subparsers.add_parser('execute', help='execute tests')
    e_parser.set_defaults(func=execute)
    e_parser.add_argument('app', metavar='app.json',
                          help='application config card')
    e_parser.add_argument('tests', metavar='test.json', nargs='+',
                          help='test config card or directory containing\
                          such cards')
    e_parser.add_argument('-o', '--output', default='benchmarks/new',
                          help='Path to benchmark directory')

    c_parser = subparsers.add_parser('compare', help='compare results')
    c_parser.set_defaults(func=compare)
    c_parser.add_argument('new', metavar='new_benchmark')
    c_parser.add_argument('old', metavar='old_benchmark')
    c_parser.add_argument('-o', '--output', default=None,
                          help='Path to JSON file of comparison results.')
    c_parser.add_argument('--rtol', type=float, default=0.01,
                          help='Relative precision at which results \
                          considered compatible')
    c_parser.add_argument('--atol', type=float, default=0.0,
                          help='Absolute precision at which results \
                          considered compatible')

    args = parser.parse_args()

    LOGFORMAT = '%(levelname)s: %(message)s'
    logging.basicConfig(level=args.LOGLEVEL, format=LOGFORMAT)

    args.func(args)
