"""ASV benchmarks for scale fixture processing.

Measures the performance of:
- Fixture metadata loading and parsing
- Threshold matrix validation
- File distribution generation from scale profiles
- Language mix validation
"""

from __future__ import annotations

import json
import math
from pathlib import Path

_FIXTURES_DIR = Path(__file__).resolve().parents[1] / "features" / "fixtures" / "scale"


def _load_fixture(filename: str) -> dict:
    """Load a JSON fixture file from the scale fixtures directory."""
    path = _FIXTURES_DIR / filename
    with open(path) as fh:
        return json.load(fh)


class ScaleFixtureSuite:
    """Benchmarks for scale fixture processing."""

    timeout = 120

    def setup(self) -> None:
        """Load scale fixtures for benchmark use."""
        self.metadata_path = _FIXTURES_DIR / "scale_metadata.json"
        self.thresholds_path = _FIXTURES_DIR / "baseline_thresholds.json"
        self.metadata = _load_fixture("scale_metadata.json")
        self.thresholds = _load_fixture("baseline_thresholds.json")

    def time_metadata_loading(self) -> None:
        """Benchmark fixture metadata loading from disk."""
        _load_fixture("scale_metadata.json")

    def time_threshold_loading(self) -> None:
        """Benchmark threshold fixture loading from disk."""
        _load_fixture("baseline_thresholds.json")

    def time_threshold_validation(self) -> None:
        """Benchmark threshold matrix validation logic."""
        data = self.thresholds
        for section in ("indexing", "decomposition"):
            for _file_count, thresholds in data[section].items():
                p50 = thresholds["p50_ms"]
                p95 = thresholds["p95_ms"]
                p99 = thresholds["p99_ms"]
                assert p50 < p95 < p99

    def time_language_mix_validation(self) -> None:
        """Benchmark language mix sum validation across all profiles."""
        for profile in self.metadata["scale_profiles"]:
            total = sum(profile["language_mix"].values())
            assert math.isclose(total, 1.0, rel_tol=1e-6)

    def time_file_distribution_generation(self) -> None:
        """Benchmark file distribution generation for all profiles."""
        for profile in self.metadata["scale_profiles"]:
            total = profile["file_count"]
            mix = profile["language_mix"]
            distribution: dict[str, int] = {}
            allocated = 0
            items = sorted(mix.items(), key=lambda x: x[1], reverse=True)
            for i, (lang, ratio) in enumerate(items):
                if i == len(items) - 1:
                    distribution[lang] = total - allocated
                else:
                    count = round(total * ratio)
                    distribution[lang] = count
                    allocated += count
            assert sum(distribution.values()) == total

    def time_full_fixture_roundtrip(self) -> None:
        """Benchmark complete fixture load + validate + distribute cycle."""
        metadata = _load_fixture("scale_metadata.json")
        thresholds = _load_fixture("baseline_thresholds.json")

        # Validate thresholds
        for section in ("indexing", "decomposition"):
            for _file_count, thresh in thresholds[section].items():
                assert thresh["p50_ms"] < thresh["p95_ms"] < thresh["p99_ms"]

        # Validate and generate distributions
        for profile in metadata["scale_profiles"]:
            total_mix = sum(profile["language_mix"].values())
            assert math.isclose(total_mix, 1.0, rel_tol=1e-6)

            total = profile["file_count"]
            mix = profile["language_mix"]
            distribution: dict[str, int] = {}
            allocated = 0
            items = sorted(mix.items(), key=lambda x: x[1], reverse=True)
            for i, (lang, ratio) in enumerate(items):
                if i == len(items) - 1:
                    distribution[lang] = total - allocated
                else:
                    count = round(total * ratio)
                    distribution[lang] = count
                    allocated += count
            assert sum(distribution.values()) == total
