#!/usr/bin/env python3
import argparse
import os
import sys
from pathlib import Path
from typing import Optional

from typeguard import typechecked

from ci.util.test_types import TestArgs


def _python_test_exists(test_name: str) -> bool:
    """Check if a Python test file exists for the given test name"""
    # Check for the test file in ci/tests directory
    tests_dir = Path("ci/tests")

    # Try various naming patterns for Python tests
    possible_names = [
        f"test_{test_name}.py",
        f"{test_name}.py",
    ]

    for name in possible_names:
        test_file = tests_dir / name
        if test_file.exists():
            return True

    return False


def parse_args(args: Optional[list[str]] = None) -> TestArgs:
    """Parse command line arguments"""
    parser = argparse.ArgumentParser(description="Run FastLED tests")
    parser.add_argument(
        "--cpp",
        action="store_true",
        help="Run C++ tests only (equivalent to --unit --examples, suppresses Python tests)",
    )
    parser.add_argument("--unit", action="store_true", help="Run C++ unit tests only")
    parser.add_argument("--py", action="store_true", help="Run Python tests only")
    parser.add_argument(
        "test",
        type=str,
        nargs="?",
        default=None,
        help="Specific test to run (Python or C++)",
    )

    # Create mutually exclusive group for compiler selection
    compiler_group = parser.add_mutually_exclusive_group()
    compiler_group.add_argument(
        "--clang", action="store_true", help="Use Clang compiler"
    )
    compiler_group.add_argument(
        "--gcc", action="store_true", help="Use GCC compiler (default on non-Windows)"
    )

    parser.add_argument(
        "--clean", action="store_true", help="Clean build before compiling"
    )
    parser.add_argument(
        "--no-interactive",
        action="store_true",
        help="Force non-interactive mode (no confirmation prompts)",
    )
    parser.add_argument(
        "--interactive",
        action="store_true",
        help="Enable interactive mode (allows confirmation prompts)",
    )
    parser.add_argument(
        "--verbose",
        "-v",
        action="store_true",
        help="Enable verbose output showing all test details",
    )
    parser.add_argument(
        "--show-compile",
        action="store_true",
        help="Show compilation commands and output",
    )
    parser.add_argument(
        "--show-link",
        action="store_true",
        help="Show linking commands and output",
    )
    parser.add_argument(
        "--quick", action="store_true", help="Enable quick mode with FASTLED_ALL_SRC=1"
    )
    parser.add_argument(
        "--no-stack-trace",
        action="store_true",
        help="Disable stack trace dumping on timeout",
    )
    parser.add_argument(
        "--check",
        action="store_true",
        help="Enable static analysis (IWYU, clang-tidy) - auto-enables --cpp and --clang",
    )
    parser.add_argument(
        "--examples",
        nargs="*",
        help="Run example compilation tests only (optionally specify example names). Use with --full for complete compilation + linking + execution",
    )
    parser.add_argument(
        "--no-pch",
        action="store_true",
        help="Disable precompiled headers (PCH) when running example compilation tests",
    )
    parser.add_argument(
        "--unity",
        action="store_true",
        help="Enable UNITY build mode for examples - compile all source files as a single unit for improved performance",
    )
    parser.add_argument(
        "--no-unity",
        action="store_true",
        help="Disable unity builds for cpp tests and examples",
    )
    parser.add_argument(
        "--full",
        action="store_true",
        help="Run full integration tests including compilation + linking + program execution",
    )

    parser.add_argument(
        "--no-parallel",
        action="store_true",
        help="Force sequential test execution",
    )
    parser.add_argument(
        "--unity-chunks",
        type=int,
        default=1,
        help="Number of unity chunks when building libfastled.a (default: 1)",
    )
    parser.add_argument(
        "--debug",
        action="store_true",
        help="Enable debug mode for C++ unit tests (e.g., full debug symbols)",
    )

    parsed_args = parser.parse_args(args)

    # Convert argparse.Namespace to TestArgs dataclass
    test_args = TestArgs(
        cpp=parsed_args.cpp,
        unit=parsed_args.unit,
        py=parsed_args.py,
        test=parsed_args.test,
        clang=parsed_args.clang,
        gcc=parsed_args.gcc,
        clean=parsed_args.clean,
        no_interactive=parsed_args.no_interactive,
        interactive=parsed_args.interactive,
        verbose=parsed_args.verbose,
        show_compile=parsed_args.show_compile,
        show_link=parsed_args.show_link,
        quick=parsed_args.quick,
        no_stack_trace=parsed_args.no_stack_trace,
        check=parsed_args.check,
        examples=parsed_args.examples,
        no_pch=parsed_args.no_pch,
        unity=parsed_args.unity,
        no_unity=parsed_args.no_unity,
        full=parsed_args.full,
        no_parallel=parsed_args.no_parallel,
        unity_chunks=parsed_args.unity_chunks,
        debug=parsed_args.debug,
    )

    # Auto-enable --py or --cpp mode when a specific test is provided
    if test_args.test:
        # Check if this is a Python test first
        if _python_test_exists(test_args.test):
            # This is a Python test - enable Python mode
            if not test_args.py and not test_args.cpp:
                test_args.py = True
                print(
                    f"Auto-enabled --py mode for specific Python test: {test_args.test}"
                )
        else:
            # This is not a Python test - assume it's a C++ test
            if not test_args.cpp and not test_args.py:
                test_args.cpp = True
                print(f"Auto-enabled --cpp mode for specific test: {test_args.test}")
            # Also enable --unit when a specific C++ test is provided without any other flags
            if (
                not test_args.unit
                and not test_args.examples
                and not test_args.py
                and not test_args.full
            ):
                test_args.unit = True
                print(f"Auto-enabled --unit mode for specific test: {test_args.test}")

    # Auto-enable --verbose when running unit tests (disabled)
    # if test_args.unit and not test_args.verbose:
    #     test_args.verbose = True
    #     print("Auto-enabled --verbose mode for unit tests")

    # Auto-enable --cpp and --clang when --check is provided
    if test_args.check:
        if not test_args.cpp:
            test_args.cpp = True
            print("Auto-enabled --cpp mode for static analysis (--check)")
        if not test_args.clang and not test_args.gcc:
            test_args.clang = True
            print("Auto-enabled --clang compiler for static analysis (--check)")

    # Auto-enable --cpp and --quick when --examples is provided
    if test_args.examples is not None:
        if not test_args.cpp:
            test_args.cpp = True
            print("Auto-enabled --cpp mode for example compilation (--examples)")
        if not test_args.quick:
            test_args.quick = True
            print(
                "Auto-enabled --quick mode for faster example compilation (--examples)"
            )

    # Handle --full flag behavior
    if test_args.full:
        if test_args.examples is not None:
            # --examples --full: Run examples with full compilation+linking+execution
            print("Full examples mode: compilation + linking + program execution")
        else:
            # --full alone: Run integration tests
            if not test_args.cpp:
                test_args.cpp = True
                print("Auto-enabled --cpp mode for full integration tests (--full)")
            print("Full integration tests: compilation + linking + program execution")

    # Default to Clang on Windows unless --gcc is explicitly passed
    if sys.platform == "win32" and not test_args.gcc and not test_args.clang:
        test_args.clang = True
        print("Windows detected: defaulting to Clang compiler (use --gcc to override)")
    elif test_args.gcc:
        print("Using GCC compiler")
    elif test_args.clang:
        print("Using Clang compiler")

    # Validate conflicting arguments
    if test_args.no_interactive and test_args.interactive:
        print(
            "Error: --interactive and --no-interactive cannot be used together",
            file=sys.stderr,
        )
        sys.exit(1)

    # Set NO_PARALLEL environment variable if --no-parallel is used
    if test_args.no_parallel:
        os.environ["NO_PARALLEL"] = "1"
        print("Forcing sequential execution (NO_PARALLEL=1)")

    return test_args
