#!/usr/bin/env python3
"""Validate machine-readable mutmut CI statistics against a score floor."""

from __future__ import annotations

import argparse
import json
import math
from pathlib import Path
from typing import Any


DEFAULT_MUTATION_SCORE_MINIMUM = 85.0


def mutation_score(stats: dict[str, Any]) -> tuple[int, int, float]:
    """Return killed, total, and percentage after validating mutmut statistics."""
    killed = stats.get("killed")
    total = stats.get("total")
    if isinstance(killed, bool) or not isinstance(killed, int) or killed < 0:
        raise ValueError("mutation statistics require a non-negative integer 'killed'")
    if isinstance(total, bool) or not isinstance(total, int) or total <= 0:
        raise ValueError("mutation statistics require a positive integer 'total'")
    if killed > total:
        raise ValueError("mutation statistics cannot report more killed mutants than total")
    return killed, total, killed / total * 100


def validate_mutation_stats(
    stats: dict[str, Any], *, minimum: float,
) -> list[str]:
    """Return failures for an incomplete run or a score below the policy floor."""
    if not math.isfinite(minimum) or minimum < 0 or minimum > 100:
        return ["minimum mutation score must be between 0 and 100"]
    try:
        killed, total, score = mutation_score(stats)
    except ValueError as exc:
        return [str(exc)]

    failures: list[str] = []
    if stats.get("check_was_interrupted_by_user"):
        failures.append("mutation run was interrupted")
    if score < minimum:
        failures.append(
            f"mutation score {score:.2f}% ({killed}/{total}) is below "
            f"the {minimum:.2f}% floor",
        )
    return failures


def _parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("stats", type=Path, help="mutmut-cicd-stats.json path")
    parser.add_argument("--minimum", type=float, default=DEFAULT_MUTATION_SCORE_MINIMUM)
    return parser


def main() -> int:
    args = _parser().parse_args()
    try:
        stats = json.loads(args.stats.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as exc:
        print(f"mutation gate failed: cannot read statistics: {exc}")
        return 1
    if not isinstance(stats, dict):
        print("mutation gate failed: statistics root must be an object")
        return 1

    failures = validate_mutation_stats(stats, minimum=args.minimum)
    if failures:
        for failure in failures:
            print(f"mutation gate failed: {failure}")
        return 1

    killed, total, score = mutation_score(stats)
    print(f"mutation gate passed: {score:.2f}% ({killed}/{total})")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
