"""The award picker at its call sites: the card corner and the product page.

`award_picker.pick` held the strategy Adam was given while the catalogue queries
still ran the first "best tier, then most recent" loop over every medal a bottle
ever won: Elijah Craig Small Batch (NYISC Double Gold 2024, Silver 2025) kept the
Double Gold in its card corner after the 2025 result came in, the product page
listed every medal from every year, and nothing knew the visitor's airports.
These tests drive `_top_awards` and `get_product` with a session shaped like the
real one and pin what each surface now shows.
"""

import pytest

from app.models import Award, ProductVariant
from app.services import catalog_queries


def award(variant_id: int, slug: str, year: int, medal: str, score: int | None = None) -> Award:
    names = {
        "nyisc": "New York International Spirits Competition",
        "bisc": "Berlin International Spirits Competition",
        "aisc": "Asia International Spirits Competition",
    }
    return Award(
        id=hash((variant_id, slug, year)) % 100_000,
        variant_id=variant_id, competition=names[slug], competition_slug=slug,
        year=year, medal=medal, score=score, is_own_competition=False,
    )


class _Rows(list):
    def all(self):
        return list(self)


class _Session:
    """`scalars` answers the award select; `get` the product; `execute` an empty price table."""

    def __init__(self, awards: list[Award], product: ProductVariant | None = None):
        self.awards = awards
        self.product = product
        self.info: dict = {}

    def scalars(self, stmt):
        return _Rows(self.awards)

    def get(self, model, pid):
        return self.product if self.product is not None and self.product.id == pid else None

    def execute(self, stmt):
        return _Rows()


ELIJAH = [award(7, "nyisc", 2024, "Double Gold", 96), award(7, "nyisc", 2025, "Silver", 90)]


class TestCardCorner:
    def test_the_latest_result_takes_the_corner_not_the_best_ever(self):
        top = catalog_queries._top_awards(_Session(ELIJAH), [7])
        assert top[7].medal == "Silver" and top[7].year == 2025 and top[7].competition_slug == "nyisc"

    def test_across_competitions_the_higher_level_among_latest_results_wins(self):
        rows = ELIJAH + [award(7, "bisc", 2024, "Gold", 94)]
        top = catalog_queries._top_awards(_Session(rows), [7])
        assert (top[7].competition_slug, top[7].medal, top[7].year) == ("bisc", "Gold", 2024)

    def test_the_visitors_airports_break_a_tie(self):
        rows = [award(7, "nyisc", 2025, "Gold", 94), award(7, "bisc", 2025, "Gold", 94)]
        assert catalog_queries._top_awards(_Session(rows), [7], ["JFK"])[7].competition_slug == "nyisc"
        assert catalog_queries._top_awards(_Session(rows), [7], ["BER"])[7].competition_slug == "bisc"
        # No airports: the same medal for everyone (competition name, then slug).
        assert catalog_queries._top_awards(_Session(rows), [7])[7].competition_slug == "bisc"

    def test_products_without_medals_have_no_corner_and_nothing_is_asked_for_none(self):
        rows = ELIJAH + [award(9, "aisc", 2023, "Bronze")]
        top = catalog_queries._top_awards(_Session(rows), [7, 9, 11])
        assert set(top) == {7, 9} and top[9].medal == "Bronze"
        assert catalog_queries._top_awards(_Session(rows), []) == {}


class TestProductPage:
    @pytest.fixture(autouse=True)
    def no_block(self, monkeypatch):
        monkeypatch.setattr(catalog_queries, "blocked_shop_ids", lambda db: [])

    def _detail(self, rows, at_codes=None):
        product = ProductVariant(id=7, name="Elijah Craig Small Batch", match_key="k", brand="Elijah Craig", is_exclusive=False)
        return catalog_queries.get_product(_Session(rows, product), 7, at_codes=at_codes)

    def test_page_lists_the_retained_medals_featured_first_and_counts_every_one_held(self):
        rows = ELIJAH + [award(7, "bisc", 2021, "Gold", 94), award(7, "bisc", 2024, "Silver", 92)]
        detail = self._detail(rows)
        # Latest per competition only (the 2024 Double Gold and the 2021 Gold step
        # back); two Silvers tie on level, so the more recent leads.
        assert [(a.competition_slug, a.year, a.medal) for a in detail.awards] == [
            ("nyisc", 2025, "Silver"), ("bisc", 2024, "Silver"),
        ]
        assert detail.top_award is not None and detail.top_award.competition_slug == "nyisc"
        assert detail.award_count == 4

    def test_the_visitors_airports_reorder_the_page_too(self):
        """Level and recency come first; the airports only settle a tie between them."""
        rows = ELIJAH + [award(7, "bisc", 2025, "Silver", 92)]
        assert self._detail(rows, ["JFK"]).awards[0].competition_slug == "nyisc"
        assert self._detail(rows, ["BER"]).awards[0].competition_slug == "bisc"
        assert self._detail(rows).awards[0].competition_slug == "bisc"  # name order, for everyone

    def test_no_medals_no_corner(self):
        detail = self._detail([])
        assert detail.awards == [] and detail.top_award is None and detail.award_count == 0

    def test_unknown_product_is_none(self):
        assert catalog_queries.get_product(_Session([], None), 7) is None
