# By: Md. Fahim Bin Amin
"""
Custom Pytest Test Runner with Function-Level Colored Output and File-Level Summary.

Features:
----------
✅ Run tests from a specified suite (e.g. unit_tests, integration_tests) or ALL if not provided
✅ Show per-test function result (PASSED/FAILED) in color
✅ Support pytest arguments (--verbose, -k, -m, etc.)
✅ Show per-file summary of passed/failed test counts at the end

How to Scale:
-------------
- Add `--report` flag to export results as JUnit or HTML (using pytest plugins)
- Add timing (e.g., show duration per test)
- Add parallelism (via pytest-xdist)
- Include filters by tag or marker (`-m smoke`)
- Integrate with CI/CD by capturing output and storing logs

Usage:
------
Run from the project root:
    python -m tests.test_run
    python -m tests.test_run --suite integration_tests
    python -m tests.test_run --suite integration_tests --verbose
    python -m tests.test_run -- -k "test_x" --tb=short
    python -m tests.test_run --suite unit_tests --verbose
    python -m tests.test_run -- -k "critical"
"""

import sys
import argparse
from pathlib import Path
import pytest
import tests.conftest_plugin

# ANSI color utility
class Colors:
    GREEN = "\033[92m"
    RED = "\033[91m"
    CYAN = "\033[96m"
    RESET = "\033[0m"

def run_pytest(test_paths: list[Path], additional_args: list[str]):
    """
    Run pytest with custom flags and one or more test paths.

    Args:
        test_paths (List[Path]): Paths to the test suite(s).
        additional_args (List[str]): Additional command-line arguments to pass to pytest.
    """
    for test_path in test_paths:
        if not test_path.exists():
            print(f"{Colors.RED}ERROR: Test path not found: {test_path}{Colors.RESET}")
            sys.exit(1)

    for test_path in test_paths:
        print(f"{Colors.CYAN}Running tests in: {test_path}{Colors.RESET}\n")

    args = [str(path) for path in test_paths] + additional_args
    pytest.main(args, plugins=[tests.conftest_plugin])

    # Summary Report (file-wise)
    print(f"\n{Colors.CYAN}======== File-Level Summary ========{Colors.RESET}")
    for file_path, result in tests.conftest_plugin.FILE_SUMMARY.items():
        passed = result.get("passed", 0)
        failed = result.get("failed", 0)
        total = passed + failed
        color = Colors.GREEN if failed == 0 else Colors.RED
        print(f"{color}{file_path}: {passed} passed, {failed} failed (total: {total}){Colors.RESET}")


def main():
    """
    Command-line entry point to parse args and invoke test runner.
    """
    parser = argparse.ArgumentParser(description="Custom Pytest Test Runner with Summary")
    parser.add_argument(
        "--suite",
        type=str,
        default=None,
        help="Test suite directory under `tests/` (e.g., unit_tests, integration_tests). If not provided, runs all subdirs."
    )
    parser.add_argument(
        "--verbose",
        action="store_true",
        help="Enable verbose test output"
    )
    parser.add_argument(
        "pytest_args",
        nargs=argparse.REMAINDER,
        help="Any extra arguments to pass to pytest (e.g. -k 'test_x' --tb=short)"
    )

    args = parser.parse_args()

    # Ensure tests root is in path
    sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
    tests_root = Path(__file__).resolve().parent

    if args.suite:
        test_paths = [tests_root / args.suite]
    else:
        # Collect all directories under tests/ that aren't special (__pycache__, etc.)
        test_paths = [p for p in tests_root.iterdir() if p.is_dir() and not p.name.startswith("__")]

    additional_args = []
    if args.verbose:
        additional_args.append("-v")
    additional_args += args.pytest_args

    run_pytest(test_paths, additional_args)


if __name__ == "__main__":
    main()
