"""`/api/stats` sends each category's family, so the mega menu can group its shelves.

The menu's categories column was designed to read as families and their
categories (Drinks: Whisky, Gin, ...; Beauty: Perfume, Skincare), and
MegaMenu.tsx groups by `family_label` the moment it arrives. No API carried the
family, so the column shipped as one flat list of fourteen shelves. The schema
fields and `taxonomy.family_label` landed first (d3f0590); this pins the one
place that fills them, `catalog_queries.category_counts`, which also feeds
`/api/dataset` and the airport and brand pages.
"""

from sqlalchemy.dialects import postgresql

from app.services import catalog_queries, verify


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


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 TestCategoryCountsCarryTheFamily:
    def test_each_count_names_its_family_and_the_shoppers_word_for_it(self, monkeypatch):
        monkeypatch.setattr(verify, "blocked_sources", lambda db: {})
        db = _Session([("Whisky", 114), ("Perfume", 40), ("Confectionery", 12), ("Tobacco", 3)])
        counts = catalog_queries.category_counts(db)
        assert [(c.category, c.count, c.family, c.family_label) for c in counts] == [
            ("Whisky", 114, "liquor", "Drinks"),
            ("Perfume", 40, "beauty", "Beauty"),
            ("Confectionery", 12, "confectionery", "Confectionery"),
            ("Tobacco", 3, "tobacco", "Tobacco"),
        ]

    def test_a_category_outside_the_vocabulary_has_no_family_and_keeps_its_count(self, monkeypatch):
        """A retailer's own label that classify() never folded still counts; the
        menu shows it ungrouped rather than inventing a family for it."""
        monkeypatch.setattr(verify, "blocked_sources", lambda db: {})
        (count,) = catalog_queries.category_counts(_Session([("View All", 7)]))
        assert (count.category, count.count, count.family, count.family_label) == ("View All", 7, None, None)

    def test_the_statement_is_unchanged(self, monkeypatch):
        """The family is looked up in Python from the category name: the query
        still counts distinct visible product variants per category and nothing more."""
        monkeypatch.setattr(verify, "blocked_sources", lambda db: {})
        db = _Session([])
        assert catalog_queries.category_counts(db) == []
        (statement,) = db.statements
        assert "count(distinct(product_variants.id))" in statement
        assert "shops.visible IS true" in statement
        assert "GROUP BY product_variants.category" in statement
