import os
import glob
import sys
import subprocess
import time
import argparse

FQBN_PREFIX='adafruit:samd:adafruit_'


parser = argparse.ArgumentParser(
    description='python wrapper for adafruit arduino CI workflows',
    allow_abbrev=False
    )
parser.add_argument(
    '--all_warnings', '--Wall',
    action='store_true',
    help='build with all warnings enabled (`--warnings all`)',
    )
parser.add_argument(
    '--warnings_do_not_cause_job_failure',
    action='store_true',
    help='failed builds will be listed as failed, but not cause job to exit with an error status',
    )
parser.add_argument(
    'build_boards',
    metavar='board',
    nargs='*',
    help='list of boards to be built -- Note that the fqbn is created by prepending "{}"'.format(FQBN_PREFIX),
    default= [ 'metro_m0', 'metro_m4', 'circuitplayground_m0' ]
    )
args = parser.parse_args()

exit_status = 0
success_count = 0
fail_count = 0
skip_count = 0
build_format = '| {:22} | {:30} | {:9} '
build_separator = '-' * 80

def errorOutputFilter(line: str):
    if len(line) == 0:
        return False
    if line.isspace(): # Note: empty string does not match here!
        return False
    # TODO: additional items to remove?
    return True

def build_examples(variant: str):
    global args, exit_status, success_count, fail_count, skip_count, build_format, build_separator

    print('\n')
    print(build_separator)
    print('| {:^76} |'.format('Board ' + variant))
    print(build_separator)
    print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time'))
    print(build_separator)
    
    fqbn = "{}{}".format(FQBN_PREFIX, variant)

    for sketch in glob.iglob('libraries/**/*.ino', recursive=True):
        start_time = time.monotonic()

        # Skip if contains: ".board.test.skip" or ".all.test.skip"
        # Skip if not contains: ".board.test.only" for a specific board
        sketchdir = os.path.dirname(sketch)
        if os.path.exists(sketchdir + '/.all.test.skip') or os.path.exists(sketchdir + '/.' + variant + '.test.skip'):
            success = "\033[33mskipped\033[0m  "
        elif glob.glob(sketchdir+"/.*.test.only") and not os.path.exists(sketchdir + '/.build.' + variant):
            success = "\033[33mskipped\033[0m  "
        else:
            # TODO - preferably, would have STDERR show up in **both** STDOUT and STDERR.
            #        preferably, would use Python logging handler to get both distinct outputs and one merged output
            #        for now, split STDERR when building with all warnings enabled, so can detect warning/error output.
            if args.all_warnings:
                build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            else:
                build_result = subprocess.run("arduino-cli compile --warnings default --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

            # get stderr into a form where len(warningLines) indicates a true warning was output to stderr
            warningLines = [];
            if args.all_warnings and build_result.stderr:
                tmpWarningLines = build_result.stderr.decode("utf-8").splitlines()
                warningLines = list(filter(errorOutputFilter, (tmpWarningLines)))

            if build_result.returncode != 0:
                exit_status = build_result.returncode
                success = "\033[31mfailed\033[0m   "
                fail_count += 1
            elif len(warningLines) != 0:
                if not args.warnings_do_not_cause_job_failure:
                    exit_status = -1
                success = "\033[31mwarnings\033[0m "
                fail_count += 1
            else:
                success = "\033[32msucceeded\033[0m"
                success_count += 1

        build_duration = time.monotonic() - start_time

        print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration))

        if success != "\033[33mskipped\033[0m  ":
            if build_result.returncode != 0:
                print(build_result.stdout.decode("utf-8"))
                if (build_result.stderr):
                    print(build_result.stderr.decode("utf-8"))
            if len(warningLines) != 0:
                for line in warningLines:
                    print(line)
        else:
            skip_count += 1

build_time = time.monotonic()

for board in args.build_boards:
    build_examples(board)

print(build_separator)
build_time = time.monotonic() - build_time
print("Build Summary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m, {} \033[33mskipped\033[0m and took {:.2f}s".format(success_count, fail_count, skip_count, build_time))
print(build_separator)

sys.exit(exit_status)
