"""Performance regression tests using pytest-benchmark.

These tests verify that key database queries and data transformations
complete within acceptable time bounds. They use ``pytest-benchmark``
for timing and store baselines for regression detection.

Run with::

    pytest tests/test_performance_regression.py --benchmark-only

To update baselines (after intentional performance changes)::

    pytest tests/test_performance_regression.py --benchmark-save=data
"""

import pytest

from packages.core.storage.models import EntityType
from packages.core.storage.repositories import (
    HorseRepository,
    MeetingRepository,
    RaceRepository,
    RatingSnapshotRepository,
)

pytestmark = pytest.mark.benchmark


# ── Helpers ────────────────────────────────────────────────────────────


def _setup_snapshots(
    db_session,
    count: int = 100,
    meeting_id: str = "bench_meeting",
    meeting_date: str = "2026-01-15",
) -> int:
    """Create ``count`` rating snapshots for benchmarking.

    Returns the ``race.id`` used for all snapshots.
    """
    meeting = MeetingRepository.upsert(
        db_session,
        {
            "meeting": meeting_id,
            "date": meeting_date,
            "name": "Benchmark Track",
            "category": "H",
        },
    )
    race = RaceRepository.upsert(
        db_session,
        meeting.id,
        {
            "race_number": 1,
            "distance": 2000,
            "advertised_start_string": f"{meeting_date}T14:30:00+13:00",
        },
    )

    # Create N unique horse snapshots
    for i in range(count):
        horse_id = 100_000 + i
        HorseRepository.upsert(db_session, horse_id, f"Bench Horse {i}")
        RatingSnapshotRepository.upsert(
            db_session,
            entity_type=EntityType.HORSE,
            entity_id=horse_id,
            as_of_race_id=race.id,
            rating=1500.0 + i * 0.5,
            rd=100.0 - i * 0.1 if i < 500 else 50.0,
            meta={"race_count": i + 1},
        )

    return race.id


# ── Benchmark: RatingSnapshotRepository.get_top_ratings ───────────────


class TestGetTopRatingsBenchmark:
    """Benchmarks for ``RatingSnapshotRepository.get_top_ratings``."""

    @pytest.mark.benchmark
    def test_get_top_ratings_100_snapshots(self, db_session, benchmark):
        """get_top_ratings should complete in <1s for 100 snapshots."""
        _setup_snapshots(db_session, count=100)

        def _query():
            return RatingSnapshotRepository.get_top_ratings(
                db_session, EntityType.HORSE, limit=10
            )

        result = benchmark(_query)

        # Baseline assertion: completes in reasonable time
        assert benchmark.stats["mean"] < 1.0, (
            f"get_top_ratings took {benchmark.stats['mean']:.3f}s "
            f"(expected <1.0s for 100 rows)"
        )

        # Correctness: should return up to 10 results
        assert len(result) <= 10
        if len(result) > 1:
            # Results should be sorted by rating descending
            ratings = [s.rating for s in result]
            assert ratings == sorted(ratings, reverse=True)


# ── Benchmark: simulated /v1/ratings/horses API response ──────────────


class TestRatingsApiBenchmark:
    """Benchmarks simulating the ``GET /v1/ratings/horses`` endpoint logic."""

    @pytest.mark.benchmark
    def test_get_horse_ratings_serialization(self, db_session, benchmark):
        """Simulate repository call + serialization for the horses ratings endpoint.

        Benchmarks the same logic path as ``GET /v1/ratings/horses`` without
        going through the HTTP layer (no FastAPI, no Pydantic validation).
        """
        _setup_snapshots(db_session, count=100)

        def _simulate_endpoint():
            # Same repository call as get_horse_ratings()
            snapshots = RatingSnapshotRepository.get_top_ratings(
                db_session, EntityType.HORSE, limit=100_000
            )

            # Same serialization logic as the endpoint
            from packages.core.storage.models import Horse

            results = []
            for snapshot in snapshots:
                horse = (
                    db_session.query(Horse)
                    .filter(Horse.id == snapshot.entity_id)
                    .first()
                )
                results.append(
                    {
                        "entity_type": "horse",
                        "entity_id": snapshot.entity_id,
                        "entity_name": horse.name if horse else None,
                        "rating": snapshot.rating,
                        "rd": snapshot.rd,
                        "race_count": (
                            snapshot.meta.get("race_count") if snapshot.meta else None
                        ),
                        "as_of_race_id": snapshot.as_of_race_id,
                    }
                )

            return results

        result = benchmark(_simulate_endpoint)

        # Baseline assertion: <1s for 100 rows
        assert benchmark.stats["mean"] < 1.0, (
            f"Ratings API serialization took {benchmark.stats['mean']:.3f}s "
            f"(expected <1.0s for 100 rows)"
        )

        # Correctness: should have 100 results
        assert len(result) == 100
        # Results sorted by rating descending
        ratings = [r["rating"] for r in result]
        assert ratings == sorted(ratings, reverse=True)
