"""Beauty identity: the concentration attribute and the targeted-40 fold.

The rows here are the ones the first discovery run (2026-09-05, task A7) joined wrongly
or nearly did. The fold behind the targeted list is the same rule migration #3 encodes:
brand + line + size keys; the concentration vetoes and never keys.
"""

import importlib.util
import pathlib

import pytest

from app.services.normalize import parse_concentration

_SCRIPT = pathlib.Path(__file__).resolve().parents[1] / "scripts" / "beauty-candidates.py"
_spec = importlib.util.spec_from_file_location("beauty_candidates", _SCRIPT)
candidates = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(candidates)


class TestConcentration:
    @pytest.mark.parametrize(("name", "expected"), [
        ("J'adore Eau de Parfum 10cl", "edp"),
        ("Tom Ford Bois Pacifique EDP 50ml", "edp"),
        ("Polo Red Eau de Toilette 125 ml", "edt"),
        ("Dior Homme Cologne 12.5cl", "edc"),
        ("Cheirosa '76 Perfume Mist 90 ml", "mist"),
        ("Burberry Goddess Parfum 100 ml", "parfum"),
        ("Y Le Parfum", "parfum"),
        ("J'adore 10cl", None),
        ("Absolue Rich Cream Refill 60ml", None),
    ])
    def test_reads_the_concentration_a_name_declares(self, name, expected):
        assert parse_concentration(name) == expected

    def test_eau_de_parfum_is_not_read_as_parfum(self):
        """Order of the rules: the bare word would otherwise win."""
        assert parse_concentration("La Vie est Belle Eau de Parfum 50 ml") == "edp"


class TestLineKey:
    def test_audience_is_part_of_the_line(self):
        """First run folded Calvin Klein's Eternity for Men with Eternity for Women
        (both 100 ml EDP at five stores) into one candidate."""
        men = candidates.line_key("Calvin Klein", "Eternity For Men")
        women = candidates.line_key("Calvin Klein", "Eternity For Women")
        assert men != women
        assert candidates.line_key("Calvin Klein", "Eternity pour Homme") == men
        assert candidates.line_key("Calvin Klein", "Eternity for Her Eau de Parfum 100 ml") == women

    def test_a_bare_number_is_the_line_not_a_size(self):
        """Sol de Janeiro numbers its scents; dropping the digits merged Cheirosa 62 and 76."""
        assert candidates.line_key("Sol de Janeiro", "Cheirosa '62 Body Mist 90 ml") == "cheirosa 62"
        assert candidates.line_key("Sol De Janeiro", "Cheirosa 76 Perfume Mist") == "cheirosa 76"
        assert candidates.line_key("Sol De Janeiro", "Cheirosa 39 24cl") == "cheirosa 39"

    def test_trademark_glyphs_do_not_glue_onto_a_word(self):
        assert candidates.line_key("Sol de Janeiro", "Delicia Drench™ Body Butter 75ml") == "delicia drench butter"
        assert candidates.line_key("CLARINS®", "Double Serum 9 50ml") == "double serum 9"

    def test_brand_words_and_format_words_leave_the_line(self):
        assert candidates.line_key("Kenzo", "Flower by Kenzo Eau de Parfum 100 ml") == "flower by"
        assert candidates.line_key("Kenzo", "Flower By Kenzo Rechargeable") == "flower by"
        assert candidates.line_key("Lancôme", "Lancôme La Vie Est Belle") == "vie est belle"

    def test_a_refill_pod_is_not_the_jar(self):
        assert candidates.line_key("Lancôme", "Absolue Rich Cream Refill 60ml") != candidates.line_key("Lancôme", "Absolue Rich Cream")

    @pytest.mark.parametrize("name", ["La Vie Est Belle Gift Set", "Good Girl Gift Set 80ml + 10ml", "Bom Dia Jet Set", "The Barber Ritual Set"])
    def test_sets_never_reach_the_list(self, name):
        assert candidates.is_set(name)


class TestConcentrationVeto:
    def _row(self, store, name):
        return candidates.Row(store, "Dior", name, 100, None, "fragrance")

    def test_declared_concentrations_split_a_fold_and_an_undeclared_row_joins_the_larger(self):
        rows = [
            self._row("BOG", "Dior Homme Eau de Toilette 100 ml"),
            self._row("PTY", "Dior Homme Eau de Toilette 100 ml"),
            self._row("SAL", "Dior Homme Eau de Parfum 100 ml"),
            self._row("CDG", "Dior Homme"),
        ]
        clusters = candidates.split_by_concentration(rows)
        assert sorted(len(c) for c in clusters) == [1, 3]
        largest = max(clusters, key=len)
        assert {r.store for r in largest} == {"BOG", "PTY", "CDG"}

    def test_nothing_declared_means_one_fold(self):
        rows = [self._row("CDG", "Dior Homme"), self._row("ATH", "Dior Homme 100ml")]
        assert len(candidates.split_by_concentration(rows)) == 1
