#!/usr/bin/env python3
# Requires: https://github.com/LordGolias/sqf

import os
import sys
import argparse
import concurrent.futures
from sqf.parser import parse
import sqf.analyzer
from sqf.exceptions import SQFParserError

addon_base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))


def get_files_to_process(basePath):
    arma_files = []
    for (root, _dirs, files) in os.walk(basePath):
        for file in files:
            if file.endswith(".sqf"):
                if file.endswith(".inc.sqf"):
                    continue
                filePath = os.path.join(root, file)
                arma_files.append(filePath)
    return arma_files


def process_file(filePath):
    errors = []
    warnings = []
    try:
        with open(filePath, "r", encoding="utf-8", errors="ignore") as file:
            content = file.read()
            if "#ASC_ignoreFile" in content:
                return (filePath, errors, warnings)
        sqfLintParse = parse(content)
        exceptions = sqf.analyzer.analyze(sqfLintParse).exceptions
        if (exceptions):
            for e in exceptions:
                if ("assigned to an outer scope" in e.message):
                    warnings.append(f"[{e.position[0]},{e.position[1]}] {e.message}")
                if ("is not from this scope" in e.message):
                    warnings.append(f"[{e.position[0]},{e.position[1]}] {e.message}")
                if ("not used" in e.message):
                    warnings.append(f"[{e.position[0]},{e.position[1]}] {e.message}")

                # most of this is just noise about macro parsing:
                # if (e.message.startswith("error")):
                #   errors.append(f"[{e.position[0]},{e.position[1]}] {e.message}")
                # else:
                #   warnings.append(f"[{e.position[0]},{e.position[1]}] {e.message}")
    except Exception as e:
        # errors.append(f"Exception {e}")
        pass
    return (filePath, errors, warnings)


def main():

    parser = argparse.ArgumentParser()
    parser.add_argument('-m', '--module', help='only search specified module addon folder', required=False, default=".")
    args = parser.parse_args()

    error_count = 0
    addon_base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
    if (args.module): addon_base_path = os.path.join(addon_base_path, "addons", args.module)
    arma_files = get_files_to_process(addon_base_path)
    print(f"Checking {len(arma_files)} files from {addon_base_path}")
    with concurrent.futures.ThreadPoolExecutor(max_workers=12) as executor:
        for (filePath, errors, warnings) in executor.map(process_file, arma_files):
            if errors or warnings:
                error_count += 1
                print(f"{filePath}")
                for e in errors:
                    print(f"  {e}")
                for e in warnings:
                    print(f"  {e}")

    print("Errors: {}".format(error_count))
    return error_count


if __name__ == "__main__":
    sys.exit(main())