# File: scripts/tools/pep604_isinstance_fix.py
# Purpose: Run Ruff UP038 auto-fixes to convert isinstance tuple unions to PEP 604 syntax.
# Context: Invoked to update tests, scripts, and domain code after taking backups.

"""Utility script to enforce PEP 604 union syntax for isinstance checks."""

from __future__ import annotations

import argparse
import shutil
import subprocess
import sys
from pathlib import Path

DEFAULT_TARGETS = [
    Path("tests"),
    Path("scripts"),
    Path("src/noveler/domain"),
]


def parse_args() -> argparse.Namespace:
    """Create a CLI parser for selecting target paths and ruff binary."""
    parser = argparse.ArgumentParser(
        description=(
            "Apply Ruff's UP038 autofix to convert tuple-based isinstance type checks "
            "into the PEP 604 union syntax."
        )
    )
    parser.add_argument(
        "paths",
        nargs="*",
        default=[str(path) for path in DEFAULT_TARGETS],
        help="Directories or files to scan (defaults to tests, scripts, domain)",
    )
    parser.add_argument(
        "--ruff-bin",
        default="ruff",
        help="Path to the Ruff executable (defaults to 'ruff' on PATH)",
    )
    parser.add_argument(
        "--preview",
        action="store_true",
        help=(
            "Only print the Ruff command without executing it; useful for dry runs "
            "or CI previews."
        ),
    )
    return parser.parse_args()


def build_command(ruff_bin: str, paths: list[str]) -> list[str]:
    """Construct the Ruff invocation for UP038 fixes."""
    command = [
        ruff_bin,
        "check",
        "--select",
        "UP038",
        "--fix",
        "--unsafe-fixes",
    ]
    command.extend(paths)
    return command


def main() -> int:
    """Validate inputs and run Ruff with the chosen parameters."""
    args = parse_args()

    if shutil.which(args.ruff_bin) is None:
        sys.stderr.write(f"Ruff executable not found: {args.ruff_bin}\n")
        return 2

    missing = [path for path in args.paths if not Path(path).exists()]
    if missing:
        sys.stderr.write(
            "Missing target paths detected:\n" + "\n".join(f"  - {path}" for path in missing) + "\n"
        )
        return 3

    command = build_command(args.ruff_bin, args.paths)

    if args.preview:
        print("Preview:", " ".join(command))
        return 0

    try:
        result = subprocess.run(command, check=False)
    except OSError as exc:  # pragma: no cover - defensive guard for exec errors
        sys.stderr.write(f"Failed to run Ruff: {exc}\n")
        return 4

    return result.returncode


if __name__ == "__main__":
    sys.exit(main())
