#!/usr/bin/env python3

import argparse, datetime, os, subprocess, sys, shutil
from pathlib import Path

parser = argparse.ArgumentParser(description="OpenMW integration tests.")
parser.add_argument(
    "example_suite",
    type=str,
    help="path to openmw example suite (use 'git clone https://gitlab.com/OpenMW/example-suite/' to get it)",
)
parser.add_argument("--omw", type=str, default="openmw", help="path to openmw binary")
parser.add_argument(
    "--workdir", type=str, default="integration_tests_output", help="directory for temporary files and logs"
)
args = parser.parse_args()

example_suite_dir = Path(args.example_suite).resolve()
example_suite_content = example_suite_dir / "game_template" / "data" / "template.omwgame"
if not example_suite_content.is_file():
    sys.exit(
        f"{example_suite_content} not found, use 'git clone https://gitlab.com/OpenMW/example-suite/' to get it"
    )

openmw_binary = Path(args.omw).resolve()
if not openmw_binary.is_file():
    sys.exit(f"{openmw_binary} not found")

work_dir = Path(args.workdir).resolve()
work_dir.mkdir(parents=True, exist_ok=True)
config_dir = work_dir / "config"
userdata_dir = work_dir / "userdata"
tests_dir = Path(__file__).resolve().parent / "data" / "integration_tests"
time_str = datetime.datetime.now().strftime("%Y-%m-%d-%H.%M.%S")


def runTest(name):
    print(f"Start {name}")
    shutil.rmtree(config_dir, ignore_errors=True)
    config_dir.mkdir()
    shutil.copyfile(example_suite_dir / "settings.cfg", config_dir / "settings.cfg")
    test_dir = tests_dir / name
    with open(config_dir / "openmw.cfg", "w", encoding="utf-8") as omw_cfg:
        omw_cfg.writelines(
            (
                f'data="{example_suite_dir}{os.sep}game_template{os.sep}data"\n',
                f'data-local="{test_dir}"\n',
                f'user-data="{userdata_dir}"\n',
                "content=template.omwgame\n",
            )
        )
        if (test_dir / "test.omwscripts").exists():
            omw_cfg.write("content=test.omwscripts\n")
    with open(config_dir / "settings.cfg", "a", encoding="utf-8") as settings_cfg:
        settings_cfg.write(
            "[Video]\n"
            "resolution x = 640\n"
            "resolution y = 480\n"
            "framerate limit = 60\n"
        )
    stdout_lines = list()
    exit_ok = True
    test_success = True
    with subprocess.Popen(
        [openmw_binary, "--replace=config", "--config", config_dir, "--skip-menu", "--no-grab", "--no-sound"],
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        encoding="utf-8",
        env={
            "OPENMW_OSG_STATS_FILE": work_dir / f"{name}.{time_str}.osg_stats.log",
            "OPENMW_OSG_STATS_LIST": "times",
            **os.environ,
        },
    ) as process:
        quit_requested = False
        for line in process.stdout:
            stdout_lines.append(line)
            words = line.split(" ")
            if len(words) > 1 and words[1] == "E]":
                print(line, end="")
            elif "Quit requested by a Lua script" in line:
                quit_requested = True
            elif "TEST_START" in line:
                w = line.split("TEST_START")[1].split("\t")
                print(f"TEST {w[2].strip()}\t\t", end="")
            elif "TEST_OK" in line:
                print(f"OK")
            elif "TEST_FAILED" in line:
                w = line.split("TEST_FAILED")[1].split("\t")
                print(f"FAILED {w[3]}\t\t")
                test_success = False
        process.wait(5)
        if not quit_requested:
            print("ERROR: Unexpected termination")
            exit_ok = False
        if process.returncode != 0:
            print(f"ERROR: openmw exited with code {process.returncode}")
            exit_ok = False
    if os.path.exists(config_dir / "openmw.log"):
        shutil.copyfile(config_dir / "openmw.log", work_dir / f"{name}.{time_str}.log")
    if not exit_ok:
        sys.stdout.writelines(stdout_lines)
    if test_success and exit_ok:
        print(f"{name} succeeded")
    else:
        print(f"{name} failed")
    return test_success and exit_ok


status = 0
for entry in tests_dir.glob("test_*"):
    if entry.is_dir():
        if not runTest(entry.name):
            status = -1
shutil.rmtree(config_dir, ignore_errors=True)
shutil.rmtree(userdata_dir, ignore_errors=True)
exit(status)
