import argparse
import os
import sys
import tempfile
from pytest_cream.fetch import fetch_tests
from pytest_cream.run import run_tests
from pytest_cream.filter import filter_tests
from pytest_cream import workflow


def main():
    parser = argparse.ArgumentParser(
        description="pytest-cream: The cream of test execution - smooth pytest workflows with intelligent orchestration",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Basic usage - run tests from a repository
  pytest-cream quick-run --repo owner/project --branch main --ws ~/workspace

  # With custom Python version (recommended for compatibility)
  pytest-cream quick-run --repo owner/project --python python3.11 --ws ~/workspace

  # Install dependencies with custom command before testing
  pytest-cream quick-run --repo owner/project \\
    --install-cmd "uv sync --extra cpu" \\
    --python python3.10 --ws ~/workspace

  # Complex project with fallback installation
  pytest-cream quick-run --repo owner/complex-project \\
    --install-cmd "poetry install --extras dev,test" \\
    --install-fallback \\
    --python python3.11 --ws ~/workspace

  # Exclude problematic tests
  pytest-cream quick-run --repo owner/project \\
    --exclude-tests "test_slow.py,test_integration/" \\
    --python python3.11 --ws ~/workspace

  # Use uv for faster dependency management
  pytest-cream quick-run --repo owner/project \\
    --install-uv --install-mode editable \\
    --python python3.11 --ws ~/workspace

For more examples and troubleshooting, see the documentation.
        """
    )
    subparsers = parser.add_subparsers(dest="command")

    # Fetch command
    fetch_parser = subparsers.add_parser(
        "fetch", 
        help="Fetch tests from a repository",
        description="Clone a repository branch to a workspace directory for testing."
    )
    fetch_parser.add_argument(
        "--repo",
        required=True,
        help="Repository to fetch from in format 'owner/repo' or full GitHub URL"
    )
    fetch_parser.add_argument(
        "--branch", 
        default="main",
        help="Git branch to checkout and fetch tests from. Default: main"
    )
    fetch_parser.add_argument(
        "--ws",
        "--workspace",
        dest="workspace",
        required=True,
        help="Directory path where the repository will be cloned. Use the same workspace across fetch/run/filter commands."
    )

    # Run command
    run_parser = subparsers.add_parser(
        "run", 
        help="Run tests and collect duration statistics",
        description="Execute tests from a workspace directory and generate duration logs for analysis."
    )
    run_parser.add_argument(
        "--ws",
        "--workspace",
        dest="workspace",
        required=True,
        help="Workspace directory containing the fetched tests. Use the same workspace from fetch command."
    )
    run_parser.add_argument(
        "--output", 
        default="test_durations.log", 
        help="Output file name for test durations (saved in workspace). Default: test_durations.log"
    )
    run_parser.add_argument(
        "--tests-dir", 
        default="tests", 
        help="Subdirectory within workspace containing test files. Default: tests"
    )
    run_parser.add_argument(
        "--python",
        dest="python_executable",
        default=None,
        help="Python executable to use (e.g., 'python3.11'). If not specified, uses current Python."
    )

    # Filter command
    filter_parser = subparsers.add_parser(
        "filter", 
        help="Filter tests by duration threshold",
        description="Parse test duration logs and filter tests into long/short categories based on execution time."
    )
    filter_parser.add_argument(
        "--ws",
        "--workspace",
        dest="workspace",
        required=True,
        help="Workspace directory containing the test durations log. Use the same workspace from fetch/run commands."
    )
    filter_parser.add_argument(
        "--input", 
        default="test_durations.log",
        help="Input file name with test durations (relative to workspace). Default: test_durations.log"
    )
    filter_parser.add_argument(
        "--output", 
        default="filtered_tests.txt",
        help="Output file name for filtered test results (saved in workspace). Default: filtered_tests.txt"
    )
    filter_parser.add_argument(
        "--threshold", 
        type=float, 
        required=True, 
        help="Duration threshold in seconds. Tests >= threshold are 'long', tests < threshold are 'short'."
    )

    # Quick-run (full workflow)
    quick_parser = subparsers.add_parser(
        "quick-run",
        help="Complete workflow: fetch tests, analyze durations, run with intelligent orchestration",
        description="Fetch tests from a repository, analyze test durations, then run long tests sequentially and short tests in parallel for optimal performance.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Basic usage with Python version specification (recommended)
  pytest-cream quick-run --repo owner/project --python python3.11 --ws ~/workspace

  # Project with custom dependencies using uv
  pytest-cream quick-run --repo owner/project \\
    --install-cmd "uv sync --extra cpu" \\
    --python python3.10 --ws ~/workspace

  # Development workflow with editable install
  pytest-cream quick-run --repo owner/project \\
    --install-mode editable --python python3.11 --ws ~/workspace

  # Exclude flaky or slow tests
  pytest-cream quick-run --repo owner/project \\
    --exclude-tests "test_integration.py,tests/slow/" \\
    --python python3.11 --ws ~/workspace
        """
    )
    quick_parser.add_argument(
        "--repo",
        default="SermetPekin/quick-tester",
        help="Repository to test in format 'owner/repo' or full GitHub URL. The repository containing the tests to run.",
    )
    quick_parser.add_argument(
        "--branch", 
        default="main", 
        help="Git branch to checkout and test. Commonly 'main', 'master', 'develop', or a feature branch name."
    )
    quick_parser.add_argument(
        "--threshold", 
        type=float, 
        default=0.5, 
        help="Duration threshold in seconds to classify tests as 'long' vs 'short'. Long tests run sequentially, short tests run in parallel. Default: 0.5 seconds."
    )
    quick_parser.add_argument(
        "--workers",
        type=int,
        default=4,
        help="Number of parallel workers for running short tests simultaneously. Higher values = faster execution but more CPU/memory usage. Default: 4.",
    )
    quick_parser.add_argument(
        "--ws",
        "--workspace",
        dest="workspace",
        default=None,
        help="Directory path where the repository will be cloned and test artifacts stored. Creates timestamped subdirectories to avoid conflicts. Required for most operations.",
    )
    quick_parser.add_argument(
        "--install-repo",
        dest="install_repo",
        default=None,
        help="Optional repository to install dependencies from before running tests (format: 'owner/repo'). Useful when the test repo needs a specific version of a package. If omitted, assumes tests can run with existing environment.",
    )
    quick_parser.add_argument(
        "--install-branch",
        dest="install_branch",
        default=None,
        help="Git branch to use when installing from --install-repo. If not specified, uses the same branch as --branch.",
    )
    quick_parser.add_argument(
        "--install-mode",
        dest="install_mode",
        default="pip",
        choices=["pip", "editable", "wheel"],
        help="Installation method for --install-repo: 'pip' (direct install, fastest), 'editable' (pip install -e, for development), 'wheel' (build wheel first, most reproducible). Default: pip.",
    )
    quick_parser.add_argument(
        "--install-uv",
        dest="install_uv",
        action="store_true",
        help="Use uv package manager instead of pip for installations. Faster and more reliable, especially in complex environments. Requires uv to be installed.",
    )
    quick_parser.add_argument(
        "--install-cmd",
        dest="install_cmd",
        default=None,
        help="Custom shell command to run for dependency installation (e.g., 'uv sync --extra cpu', 'poetry install --extras dev,test'). Use semicolon to chain commands. Overrides --install-mode when provided. Runs in the cloned repository directory.",
    )
    quick_parser.add_argument(
        "--install-fallback",
        dest="install_fallback",
        action="store_true",
        help="If --install-cmd fails, automatically fallback to standard pip installation instead of aborting. Useful for trying modern tools with pip as backup.",
    )
    quick_parser.add_argument(
        "--exclude-tests",
        dest="exclude_tests",
        default=None,
        help="Comma-separated list of test file patterns or directories to skip (e.g., 'test_integration.py,tests/slow,test_gpu*'). Supports glob patterns. Useful for excluding flaky, slow, or environment-specific tests.",
    )
    quick_parser.add_argument(
        "--python",
        dest="python_executable",
        default=None,
        help="Python executable to use for running tests (e.g., 'python3.11', '/usr/bin/python3.10'). IMPORTANT: Specify this to avoid 'python command not found' errors on macOS/Linux systems. If not specified, uses the current Python interpreter.",
    )

    args = parser.parse_args()

    if args.command == "fetch":
        # Validate and create workspace
        os.makedirs(args.workspace, exist_ok=True)
        output_dir = os.path.join(args.workspace, f"{args.repo.replace('/', '_')}_{args.branch}")
        extracted_path = fetch_tests(branch=args.branch, repo=args.repo, output_dir=output_dir)
        print(f"Tests fetched to: {extracted_path}")
        
    elif args.command == "run":
        # Validate workspace exists
        if not os.path.exists(args.workspace):
            print(f"Error: Workspace '{args.workspace}' does not exist. Run fetch command first.", file=sys.stderr)
            sys.exit(1)
        
        # Resolve paths relative to workspace
        tests_path = os.path.join(args.workspace, args.tests_dir)
        output_path = os.path.join(args.workspace, args.output)
        
        run_tests(
            output_file=output_path, 
            tests_dir=tests_path,
            python_executable=args.python_executable
        )
        print(f"Test durations saved to: {output_path}")
        
    elif args.command == "filter":
        # Validate workspace exists
        if not os.path.exists(args.workspace):
            print(f"Error: Workspace '{args.workspace}' does not exist. Run fetch/run commands first.", file=sys.stderr)
            sys.exit(1)
        
        # Resolve paths relative to workspace
        input_path = os.path.join(args.workspace, args.input)
        output_path = os.path.join(args.workspace, args.output)
        
        if not os.path.exists(input_path):
            print(f"Error: Input file '{input_path}' does not exist. Run the run command first.", file=sys.stderr)
            sys.exit(1)
        
        filter_tests(
            input_file=input_path, 
            output_file=output_path, 
            threshold=args.threshold
        )
        print(f"Filtered tests saved to: {output_path}")
    elif args.command == "quick-run":
        # If workspace is provided, validate it upfront and fail fast if it's not usable.
        if args.workspace:
            try:
                # Try to create the workspace directory if missing
                os.makedirs(args.workspace, exist_ok=True)
                # Try creating and removing a temporary file to verify writability
                fd, tmpfile = tempfile.mkstemp(dir=args.workspace)
                os.close(fd)
                os.remove(tmpfile)
            except Exception as e:
                print(
                    f"Error: cannot use workspace '{args.workspace}': {e}",
                    file=sys.stderr,
                )
                sys.exit(2)

        # Parse exclude patterns if provided
        exclude_tests = []
        if args.exclude_tests:
            exclude_tests = [pattern.strip() for pattern in args.exclude_tests.split(",") if pattern.strip()]

        workflow.quick_run(
            repo_url=args.repo,
            branch=args.branch,
            workspace=args.workspace,
            install_repo=args.install_repo,
            install_branch=args.install_branch,
            install_mode=args.install_mode,
            install_cmd=args.install_cmd,
            install_fallback=args.install_fallback,
            exclude_tests=exclude_tests,
            threshold=args.threshold,
            workers=args.workers,
            python_executable=args.python_executable,
        )
    else:
        parser.print_help()
