# retoor <retoor@molodetz.nl>
from __future__ import annotations

import math
from dataclasses import dataclass

from devplacepy.services.jobs.isslop.analysis.metrics import FileMetrics
from devplacepy.services.jobs.isslop.analysis.signals import AXIS_ORIGIN, SEVERITY_MEDIUM, Signal

MIN_FILES_FOR_BASELINE: int = 8
DEVIATION_Z_THRESHOLD: float = 2.0


@dataclass(frozen=True)
class RepoBaselines:
    file_count: int
    indent_variance_mean: float
    indent_variance_std: float
    comment_ratio_mean: float
    comment_ratio_std: float
    blank_ratio_mean: float
    blank_ratio_std: float


def _mean_std(values: list[float]) -> tuple[float, float]:
    if not values:
        return 0.0, 0.0
    mean = sum(values) / len(values)
    variance = sum((value - mean) ** 2 for value in values) / len(values)
    return mean, math.sqrt(variance)


def compute_baselines(metrics_by_file: dict[str, FileMetrics]) -> RepoBaselines:
    indent = [metrics.indent_variance for metrics in metrics_by_file.values() if metrics.sloc > 10]
    comment = [metrics.comment_ratio for metrics in metrics_by_file.values() if metrics.sloc > 10]
    blank = [metrics.blank_ratio for metrics in metrics_by_file.values() if metrics.sloc > 10]
    indent_mean, indent_std = _mean_std(indent)
    comment_mean, comment_std = _mean_std(comment)
    blank_mean, blank_std = _mean_std(blank)
    return RepoBaselines(
        file_count=len(indent),
        indent_variance_mean=indent_mean,
        indent_variance_std=indent_std,
        comment_ratio_mean=comment_mean,
        comment_ratio_std=comment_std,
        blank_ratio_mean=blank_mean,
        blank_ratio_std=blank_std,
    )


def deviation_signals(relative: str, metrics: FileMetrics, baselines: RepoBaselines) -> list[Signal]:
    if baselines.file_count < MIN_FILES_FOR_BASELINE or metrics.sloc <= 10:
        return []
    scores: list[float] = []
    if baselines.indent_variance_std > 0.01:
        scores.append((baselines.indent_variance_mean - metrics.indent_variance) / baselines.indent_variance_std)
    if baselines.comment_ratio_std > 0.01:
        scores.append((metrics.comment_ratio - baselines.comment_ratio_mean) / baselines.comment_ratio_std)
    if not scores:
        return []
    composite = sum(scores) / len(scores)
    if composite >= DEVIATION_Z_THRESHOLD:
        return [
            Signal(
                code="CONVENTION_DEVIATION",
                title=f"File is markedly cleaner and more regular than repo baseline (z={composite:.1f})",
                severity=SEVERITY_MEDIUM,
                axis=AXIS_ORIGIN,
                weight=3.0,
                line=1,
                evidence=f"indent deviation {metrics.indent_variance:.2f} vs repo mean {baselines.indent_variance_mean:.2f}",
            )
        ]
    return []
