"""File-size and naming validation for the managed testing surface."""

from __future__ import annotations

import re
from collections.abc import Iterable
from pathlib import Path
from typing import Any


def _expand_globs(root: Path, patterns: Iterable[str]) -> list[Path]:
    """Expand a set of relative glob patterns to unique file paths."""
    matched: set[Path] = set()
    for pattern in patterns:
        matched.update(path for path in root.glob(pattern) if path.is_file())
    return sorted(matched)


def run_check(contract: dict[str, Any], root: Path) -> list[str]:
    """Return human-readable issues for naming and file-size rules."""
    config = contract.get("hygiene", {})
    max_lines = int(config.get("max_lines", 500))
    issues: list[str] = []

    for path in _expand_globs(root, config.get("line_limit_globs", [])):
        line_count = sum(1 for _ in path.open("r", encoding="utf-8"))
        if line_count > max_lines:
            issues.append(f"file exceeds {max_lines} LOC: {path.relative_to(root)} ({line_count})")

    for rule in config.get("naming_rules", []):
        pattern = re.compile(rule["pattern"])
        for path in _expand_globs(root, [rule["glob"]]):
            if path.name == "conftest.py":
                continue
            if not pattern.match(path.name):
                issues.append(
                    f"naming rule failed ({rule['description']}): {path.relative_to(root)}"
                )

    return issues


def count_files_over_line_limit(contract: dict[str, Any], root: Path) -> int:
    """Return the number of managed files that exceed the configured LOC cap."""

    config = contract.get("hygiene", {})
    max_lines = int(config.get("max_lines", 500))
    count = 0
    for path in _expand_globs(root, config.get("line_limit_globs", [])):
        line_count = sum(1 for _ in path.open("r", encoding="utf-8"))
        if line_count > max_lines:
            count += 1
    return count


def count_files_with_line_limit(contract: dict[str, Any], root: Path) -> int:
    """Return the number of managed files included in the LOC cap."""

    config = contract.get("hygiene", {})
    return len(_expand_globs(root, config.get("line_limit_globs", [])))
