#!/usr/bin/env python3
"""
McRogueFace Test Runner
Runs all headless tests and reports results.

Usage:
    python3 tests/run_tests.py           # Run all tests
    python3 tests/run_tests.py unit      # Run only unit tests
    python3 tests/run_tests.py -v        # Verbose output
"""
import os
import subprocess
import sys
import time
import hashlib
from pathlib import Path

# Configuration
TESTS_DIR = Path(__file__).parent
BUILD_DIR = TESTS_DIR.parent / "build"
MCROGUEFACE = BUILD_DIR / "mcrogueface"
TIMEOUT = 10  # seconds per test

# Test directories to run (in order)
TEST_DIRS = ['unit', 'integration', 'regression']

# ANSI colors
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
RESET = '\033[0m'
BOLD = '\033[1m'

def get_screenshot_checksum(test_dir):
    """Get checksums of any PNG files in build directory."""
    checksums = {}
    for png in BUILD_DIR.glob("*.png"):
        with open(png, 'rb') as f:
            checksums[png.name] = hashlib.md5(f.read()).hexdigest()[:8]
    return checksums

def run_test(test_path, verbose=False):
    """Run a single test and return (passed, duration, output)."""
    start = time.time()

    # Clean any existing screenshots
    for png in BUILD_DIR.glob("test_*.png"):
        png.unlink()

    try:
        result = subprocess.run(
            [str(MCROGUEFACE), '--headless', '--exec', str(test_path)],
            capture_output=True,
            text=True,
            timeout=TIMEOUT,
            cwd=str(BUILD_DIR)
        )
        duration = time.time() - start
        passed = result.returncode == 0
        output = result.stdout + result.stderr

        # Check for PASS/FAIL in output
        if 'FAIL' in output and 'PASS' not in output.split('FAIL')[-1]:
            passed = False

        return passed, duration, output

    except subprocess.TimeoutExpired:
        return False, TIMEOUT, "TIMEOUT"
    except Exception as e:
        return False, 0, str(e)

def find_tests(directory):
    """Find all test files in a directory."""
    test_dir = TESTS_DIR / directory
    if not test_dir.exists():
        return []
    return sorted(test_dir.glob("*.py"))

def main():
    verbose = '-v' in sys.argv or '--verbose' in sys.argv

    # Determine which directories to test
    dirs_to_test = []
    for arg in sys.argv[1:]:
        if arg in TEST_DIRS:
            dirs_to_test.append(arg)
    if not dirs_to_test:
        dirs_to_test = TEST_DIRS

    print(f"{BOLD}McRogueFace Test Runner{RESET}")
    print(f"Testing: {', '.join(dirs_to_test)}")
    print("=" * 60)

    results = {'pass': 0, 'fail': 0, 'total_time': 0}
    failures = []

    for test_dir in dirs_to_test:
        tests = find_tests(test_dir)
        if not tests:
            continue

        print(f"\n{BOLD}{test_dir}/{RESET} ({len(tests)} tests)")

        for test_path in tests:
            test_name = test_path.name
            passed, duration, output = run_test(test_path, verbose)
            results['total_time'] += duration

            if passed:
                results['pass'] += 1
                status = f"{GREEN}PASS{RESET}"
            else:
                results['fail'] += 1
                status = f"{RED}FAIL{RESET}"
                failures.append((test_dir, test_name, output))

            # Get screenshot checksums if any were generated
            checksums = get_screenshot_checksum(BUILD_DIR)
            checksum_str = ""
            if checksums:
                checksum_str = f" [{', '.join(f'{k}:{v}' for k,v in checksums.items())}]"

            print(f"  {status} {test_name} ({duration:.2f}s){checksum_str}")

            if verbose and not passed:
                print(f"    Output: {output[:200]}...")

    # Summary
    print("\n" + "=" * 60)
    total = results['pass'] + results['fail']
    pass_rate = (results['pass'] / total * 100) if total > 0 else 0

    print(f"{BOLD}Results:{RESET} {results['pass']}/{total} passed ({pass_rate:.1f}%)")
    print(f"{BOLD}Time:{RESET} {results['total_time']:.2f}s")

    if failures:
        print(f"\n{RED}{BOLD}Failures:{RESET}")
        for test_dir, test_name, output in failures:
            print(f"  {test_dir}/{test_name}")
            if verbose:
                # Show last few lines of output
                lines = output.strip().split('\n')[-5:]
                for line in lines:
                    print(f"    {line}")

    sys.exit(0 if results['fail'] == 0 else 1)

if __name__ == '__main__':
    main()
