"""What is cleaning the data right now, read from the code that does it.

Sources of truth: this module, `normalize.py` and `product_lines.py` (the rules themselves),
`proposal_rules.py` (the lists that only suggest), `routers/review.py`
(`GET /api/review/collection-rules`), `tests/test_collection_rules.py`.

The review guide's first half answers one question for a reviewer: *what is folding my data, right
now?* So this reports the rules that ACT, one line each, with their own words and counts taken
from the modules that hold them. Nothing here is a second copy of a rule: the words come from
`product_lines.ATTRIBUTE_LABELS` and `proposal_rules._describe()`, so a list that gains a word
gains it here at the next deploy and a list that stops acting stops saying it does.

It deliberately carries no history, no version line and no reasoning. Why a rule exists lives in
`docs/REVIEW-PROCESS.md`; what it does lives here, because a person about to review a brand needs
the second and not the first.
"""

from __future__ import annotations

from typing import Any

#: One entry per rule that ACTS on collected data. `applies_to` is the shopper-facing vertical or
#: "every listing"; `example` is read by a person as the whole explanation when the sentence is not.
_ACTING: list[dict[str, Any]] = [
    {
        "key": "brand_row",
        "name": "A listed brand is folded to one brand row",
        "what": "Case, accents, punctuation and the trademark glyphs are folded, so the spellings a shop sends "
                "land on one brand. Nothing else is folded: a trailing word is never dropped, so two names that "
                "differ by a real word stay two brands until a person joins them.",
        "applies_to": "every listing",
        "example": "“Lancôme”, “Lancome” and “LANCOME” are one brand; “Tanqueray Gin” and “Tanqueray” are two.",
    },
    {
        "key": "quantity",
        "name": "A stated size becomes the quantity",
        "what": "A number with its unit, read from the name or the shop's own size field. A figure taken from a "
                "slug, a parent SKU or a family tile is not stated and is not read.",
        "applies_to": "every listing",
        "example": "“100 ml”, “1L”, “3.5 g”, “6 pcs”.",
    },
    {
        "key": "abv",
        "name": "A stated alcohol percentage becomes an attribute",
        "what": "It leaves the name and sits on the variant, so it compares as a number. Two different stated "
                "strengths never merge on their own.",
        "applies_to": "drinks",
        "example": "“40%”, “43% vol”; 40 and 40.0 are the same.",
    },
    {
        "key": "pack",
        "name": "A pack figure is read as a pack",
        "what": "The count and the member quantity, kept together, so a twin pack is not read as one large bottle.",
        "applies_to": "every listing",
        "example": "“3x1L”, “2 x 50 ml”.",
    },
    {
        "key": "options",
        "name": "A shop's own option field becomes an attribute",
        "what": "A value the shop published as its own field is certain, and tells that shop's variants apart. "
                "The same words found loose in a name are not, and become a suggestion instead.",
        "applies_to": "every listing",
        "example": "A shop's “Shade: 99 Pirate” is read; “… - 447 Mellow Shade” inside a name is only suggested.",
    },
    {
        "key": "concentration",
        "name": "A fragrance concentration folds to one word",
        "what": "A closed vocabulary, matched as whole words, longest phrase first, case and accents ignored. "
                "Variants at different concentrations sit in one product line and are told apart by it.",
        "applies_to": "beauty",
        "example": None,  # filled from ATTRIBUTE_LABELS
    },
    {
        "key": "age",
        "name": "The spellings of a stated age fold to one token",
        "what": "The token stays in the name: whether an age names its own product line is a judgement, not a "
                "rule. A bare number states no age and is left alone.",
        "applies_to": "drinks",
        "example": "“12 Years Old”, “12 YO”, “12 ans” and “Aged 12 Years” are one; a bare “12” is not an age.",
    },
    {
        "key": "glyphs",
        "name": "Case, accents, punctuation and glyphs fold",
        "what": "Upper and lower case, diacritics, curly and straight quotes, fullwidth digits, runs of "
                "punctuation. A fold never removes a word.",
        "applies_to": "every listing",
        "example": "“N°5” and “No 5”; “V.S.O.P.” and “VSOP”.",
    },
]


def read(db=None) -> dict[str, Any]:
    """The rules that act, and the word lists that do not. Reads no database unless one is given
    (the lists' counts of what they have suggested). Writes nothing."""
    from app.services import product_lines

    acting = []
    for rule in _ACTING:
        row = dict(rule)
        if rule["key"] == "concentration":
            labels = [product_lines.ATTRIBUTE_LABELS[k] for k in ("edp", "edt", "edc", "parfum", "mist", "elixir")
                      if k in product_lines.ATTRIBUTE_LABELS]
            qualifiers = [product_lines.ATTRIBUTE_LABELS[k] for k in ("intense", "extreme", "absolu")
                          if k in product_lines.ATTRIBUTE_LABELS]
            row["example"] = f"{', '.join(labels)}; kept beside them: {', '.join(qualifiers)}."
        acting.append(row)

    suggesting = []
    try:
        from app.services import proposal_rules

        for item in proposal_rules._describe():
            if item.get("acts"):
                continue
            suggesting.append({"key": item["key"], "name": item["key"].replace("_", " "),
                               "what": item["what"], "word_count": len(item.get("words") or []),
                               "verticals": item.get("verticals") or []})
    except Exception:  # a list that cannot be read is reported as absent, never invented
        suggesting = []
    return {"acting": acting, "suggesting": suggesting}
