from dataclasses import dataclass


@dataclass(frozen=True)
class ReviewabilityConfig:
    """Parsed reviewability configuration.

    All numeric values come from the config file (defaults.toml or user override).
    This is a pure data structure with no hardcoded defaults.
    Optional fields default to None (disabled).
    """

    hunk_score_threshold: float
    """Hunks with a reviewability score below this are considered problematic."""

    file_score_threshold: float
    """Files with a reviewability score below this are considered problematic."""

    max_diff_lines: int
    """Maximum total lines changed across the diff (used for score normalisation)."""

    max_hunk_lines: int
    """Maximum lines changed in a single hunk (used for score normalisation)."""

    rewrite_in_place_line_cost: float
    """Effective line cost for hunks classified as in-place complex rewrites."""

    rewrite_moved_line_cost: float
    """Effective line cost for hunks classified as moved complex rewrites."""

    movement_hunk_min_lines: int
    """Minimum content lines in a hunk to be considered for movement detection."""

    movement_file_min_lines: int
    """Minimum content lines in a file to be considered for movement detection."""

    movement_similarity_threshold: float
    """Fraction of lines that must match for two blocks to be classified as a movement."""

    min_overall_score: float | None = None
    """Overall diff score below this causes the gate to fail. Range [0.0, 1.0]."""

    max_problematic_hunks: int | None = None
    """Maximum number of problematic hunks allowed."""

    max_problematic_files: int | None = None
    """Maximum number of problematic files allowed."""

    max_file_hunk_count: int | None = None
    """Maximum number of hunks in a single file."""

    max_files_changed: int | None = None
    """Maximum number of files changed in the diff."""

    max_added_lines: int | None = None
    """Maximum total added lines across the diff."""
