"""The header's departments: Airports, Drinks and Beauty, each with its own panel.

The single browse panel it replaced (11 Sep) ranked every brand by product count
in one list, so 9 of its 12 "top brands" were fragrance brands beside Johnnie
Walker, and it opened on Beauty because Perfume outnumbered Wine. A department
panel lists its own shelves and its own brands, which needs two things from the
API: the shown categories of a family (what "All drinks" browses) and each
brand's family (where most of its product variants sit).
"""

from sqlalchemy.dialects import postgresql

from app.services import catalog_queries, seo, taxonomy


def _sql(clause) -> str:
    return str(clause.compile(dialect=postgresql.dialect(), compile_kwargs={"literal_binds": True}))


class TestCategoriesOfAFamily:
    def test_drinks_is_every_liquor_shelf(self):
        drinks = taxonomy.categories_of("liquor")
        assert {"Whisky", "Wine", "Champagne & Sparkling", "Beer & Cider"} <= set(drinks)
        assert "Perfume" not in drinks

    def test_a_hidden_shelf_stays_out_of_its_family(self):
        """Skincare is collected but hidden (11 Sep); "All beauty" must not show it."""
        assert taxonomy.categories_of("beauty") == ["Perfume", "Makeup"]
        assert taxonomy.categories_of("confectionery") == []

    def test_an_unknown_family_names_no_shelf(self):
        assert taxonomy.categories_of("fashion") == []
        assert taxonomy.categories_of(None) == []


class TestMajorityFamily:
    def test_a_fragrance_house_is_beauty(self):
        # Mostly perfume, some makeup: the shape of the brands that led the old list.
        assert taxonomy.majority_family({"Perfume": 101, "Makeup": 18}) == "beauty"

    def test_a_house_belongs_where_its_shelf_is(self):
        """A fashion label with one whisky is still a beauty brand; a spirits
        brand with a gift perfume is still drinks."""
        assert taxonomy.majority_family({"Perfume": 40, "Whisky": 1}) == "beauty"
        assert taxonomy.majority_family({"Whisky": 55, "Liqueurs & Aperitifs": 3, "Perfume": 1}) == "liquor"

    def test_families_sum_across_their_categories(self):
        # Two liquor shelves outweigh one bigger beauty shelf.
        assert taxonomy.majority_family({"Perfume": 10, "Wine": 6, "Champagne & Sparkling": 6}) == "liquor"

    def test_a_tie_never_depends_on_row_order(self):
        assert taxonomy.majority_family({"Whisky": 5, "Perfume": 5}) == "beauty"
        assert taxonomy.majority_family({"Perfume": 5, "Whisky": 5}) == "beauty"

    def test_no_known_family_is_none(self):
        assert taxonomy.majority_family({None: 4, "View All": 2}) is None
        assert taxonomy.majority_family({}) is None


class _Result:
    def __init__(self, rows):
        self.rows = rows

    def all(self):
        return list(self.rows)


class _Session:
    """Answers the one grouped count with fixture rows and records the statement."""

    def __init__(self, rows):
        self.info: dict = {}
        self.rows = list(rows)
        self.statements: list[str] = []

    def execute(self, stmt):
        self.statements.append(_sql(stmt))
        return _Result(self.rows)

    def scalars(self, stmt):  # the block lookup never runs: nothing is blocked
        raise AssertionError(_sql(stmt))


class TestHouseFamilies:
    def test_each_house_gets_the_family_of_its_product_variants(self, monkeypatch):
        monkeypatch.setattr(catalog_queries.verify, "blocked_sources", lambda db: {})
        db = _Session([(1, "Perfume", 101), (1, "Makeup", 18), (2, "Whisky", 69), (3, None, 9)])
        assert catalog_queries._brand_families(db, [1, 2, 3]) == {1: "beauty", 2: "liquor", 3: None}
        (statement,) = db.statements
        # The same visible listings the listed_brand floor counts, grouped per brand and shelf.
        assert "count(DISTINCT product_variants.id)" in statement
        assert "shops.is_catalogue_only IS false" in statement
        assert "GROUP BY brand_of, product_variants.category" in statement

    def test_no_houses_asks_nothing(self):
        db = _Session([])
        assert catalog_queries._brand_families(db, []) == {}
        assert db.statements == []


class TestHeaderDepartments:
    def test_the_departments_are_the_taxonomys_families(self):
        """The nav's words are typed in SiteHeader.tsx and here, because the row
        renders before any request; they must stay the taxonomy's own words."""
        for key, to, label in seo._DEPARTMENTS:
            if key in ("airports", "articles"):
                assert to == f"/{key}"
                continue
            assert taxonomy.FAMILY_LABEL[key] == label
            assert to == f"/products?family={key}"
            assert taxonomy.categories_of(key), f"{label} would open an empty department"
