"""Shared pytest factories for creating mock database records.

Usage:
    from tests.fixtures.common import meeting_factory, race_factory

    def test_something(db_session):
        meeting = meeting_factory(db_session)
        race = race_factory(db_session, meeting.id)
        ...
"""

from datetime import date

from sqlalchemy.orm import Session

from packages.core.storage.models import (
    EntityType,
    Meeting,
    Race,
    RatingSnapshot,
    Starter,
)
from packages.core.storage.repositories import (
    HorseRepository,
    MeetingRepository,
    RaceRepository,
    RatingSnapshotRepository,
    StarterRepository,
)


def meeting_factory(
    session: Session,
    meeting_id: str = "test_meeting_001",
    meeting_date: date | None = None,
    venue: str = "Test Track",
    category: str = "H",
) -> Meeting:
    """Create a Meeting record. Defaults to harness racing at Test Track."""
    if meeting_date is None:
        meeting_date = date(2026, 1, 1)
    return MeetingRepository.upsert(
        session,
        {
            "meeting": meeting_id,
            "date": meeting_date.isoformat(),
            "name": venue,
            "category": category,
        },
    )


def race_factory(
    session: Session,
    meeting_id: str,
    race_number: int = 1,
    distance: int = 2000,
    start_type: str = "mobile",
    gait: str = "pace",
    **extra: str,
) -> Race:
    """Create a Race record under the given meeting."""
    data: dict = {
        "race_number": race_number,
        "distance": distance,
        "start_type": start_type,
        "gait": gait,
    }
    data.update(extra)
    return RaceRepository.upsert(session, meeting_id, data)


def starter_factory(
    session: Session,
    race_id: int,
    horse_id: int = 10001,
    horse_name: str = "Test Horse",
    runner_number: int = 1,
    barrier: int = 1,
    placing: int | None = None,
    **extra: str | int | bool,
) -> Starter:
    """Create a Starter record under the given race.

    Also creates the referenced Horse via ``HorseRepository.upsert``.
    """
    data: dict = {
        "name": horse_name,
        "horse_id": horse_id,
        "horse_name": horse_name,
        "runner_number": runner_number,
        "barrier": barrier,
    }
    data.update(extra)  # type: ignore[arg-type]
    return StarterRepository.upsert(session, race_id, data, placing=placing)  # type: ignore[arg-type]


def horse_factory(
    session: Session,
    horse_id: int = 20001,
    name: str = "Factory Horse",
) -> None:
    """Create a Horse record directly without a race context."""
    HorseRepository.upsert(session, horse_id, name)


def snapshot_factory(
    session: Session,
    entity_type: EntityType = EntityType.HORSE,
    entity_id: int = 30001,
    race_id: int = 1,
    rating: float = 1500.0,
    rd: float | None = 100.0,
    meta: dict | None = None,
) -> RatingSnapshot:
    """Create a RatingSnapshot record."""
    return RatingSnapshotRepository.upsert(
        session,
        entity_type=entity_type,
        entity_id=entity_id,
        as_of_race_id=race_id,
        rating=rating,
        rd=rd,
        meta=meta or {},
    )
