#!/usr/bin/env python3
# -*- coding: utf8 -*-
# SPDX-FileCopyrightText: 2015-2023 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

from __future__ import print_function

import argparse
import glob
import os
import subprocess
import sys
from os.path import basename, dirname, isdir, join, realpath
try:
    from typing import Iterator  # noqa: F401
except ImportError:
    pass


TESTFOLDER = 'tests'
LIBFOLDER = 'lib'

if not isdir(TESTFOLDER):
    TESTFOLDER = join(dirname(realpath(__file__)), 'tests')
if not isdir(LIBFOLDER):
    LIBFOLDER = join(dirname(realpath(__file__)), 'lib')

# Append the usi-check libs to python path
ENV = os.environ.copy()
if 'PYTHONPATH' not in ENV:
    ENV['PYTHONPATH'] = LIBFOLDER
else:
    ENV['PYTHONPATH'] += os.pathsep + LIBFOLDER


def getUSILocation(currentDir):  # type: (str) -> str
    if currentDir.startswith('univention-support-info'):
        BASEDIR = currentDir
    elif 'univention-support-info' in currentDir:
        return currentDir
    else:
        BASEDIR = join(currentDir, 'univention-support-info')

    if not isdir(BASEDIR):
        if isdir(join(currentDir, 'files')) and isdir(join(currentDir, 'info')):
            return currentDir
        else:
            # TODO give better info on error
            raise IOError('Base directory not found! [%s]' % (BASEDIR))

    # get sub folders
    dirs = [name for name in os.listdir(BASEDIR) if isdir(join(BASEDIR, name))]
    if len(dirs) == 1:
        return join(BASEDIR, dirs[0])
    elif len(dirs) == 0:
        print("ERROR - dirs: %s | BASEDIR: '%s'" % (repr(dirs), BASEDIR))
    else:
        # TODO selectable subdir
        print("%s" % (repr(dirs)))

    return BASEDIR


class Test:
    def __init__(self, script, category, usi):  # type: (str, str, str) -> None
        self.script = script
        self.category = category
        self.usi = usi
        self.executed = False
        self.result = ""
        self.exitcode = -1

    def __str__(self):  # type: () -> str
        return self.category + '/' + self.script + ': ' + repr(self.result)

    def run(self, verbose):  # type: (bool) -> None
        self.executed = True
        filename = join(TESTFOLDER, self.category, self.script)
        process = subprocess.Popen([filename, self.usi], env=ENV, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
        stdout, stderr = process.communicate()
        # FIXME: Only print stderr in verbose mode
        if stderr and verbose:
            sys.stderr.write(self.script + ':\n')
            sys.stderr.write(stderr.decode("utf-8", "replace"))

        self.exitcode = process.returncode
        self.result = stdout.decode("utf-8", "replace")

    def report(self, verbose):  # type: (bool) -> None
        if self.executed and (self.exitcode != 0 or verbose):
            print(self.script)
            for line in self.result.split('\n'):
                print("  %s" % (line.rstrip()))


def getTests(category='*'):  # type: (str) -> Iterator[Test]
    '''
    fetches all available tests and initializes them
    these should be specified as bash/python scripts underneath folder tests/category
    '''
    for cat in sorted(category.split(',')):
        for fpath in sorted(glob.glob(join(TESTFOLDER, cat, '*'))):
            yield Test(
                script=basename(fpath),
                category=basename(dirname(fpath)),
                usi=options.usi,
            )


def parse_args():  # type: () -> argparse.Namespace
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--category", "-c",
        help="specify category",
        default='*',
    )
    parser.add_argument(
        "--noskip", "-n",
        action="store_false",
        help="dont't skip successful test",
        dest="skip_empty",
    )
    parser.add_argument(
        "--verbose", "-v",
        action="store_true",
        help="be verbose",
    )
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument(
        "--usi", "-u",
        default=argparse.SUPPRESS,
        help="specify usi-folder",
    )
    group.add_argument(
        "usi",
        nargs="?",
        default=argparse.SUPPRESS,
        help="specify usi-folder",
    )
    parser.set_defaults(usi=None)

    args = parser.parse_args()
    if not args.usi:
        args.usi = getUSILocation(os.getcwd())

    args.usi = join(realpath(args.usi))

    return args


if __name__ == '__main__':
    options = parse_args()

    print("Support-Info-Archiv report for '%s'\n" % (options.usi,))
    last_cat = ''
    for test in getTests(options.category):
        if options.verbose:
            print("running test '%s'..." % (test.script))
        test.run(options.verbose)
        if test.exitcode > 0 or not options.skip_empty:
            if last_cat != test.category:
                print("\033[36;1mCategory: %s\033[0m" % (test.category))
                last_cat = test.category
            test.report(options.verbose)
