"""Identity rules v3: the key is house | line | variation | size, with a form marker.

The fourteen 1 Million rows (Stream M brief, M3): under one house, the two 100 ml Eau de
Toilette spellings share a key and the two 200 ml Elixirs share a key even though their
parsed concentrations differ; the bare "1 Million 10cl" keys apart from both the Eau de
Toilette and the Parfum at 100 ml, because an unknown variation is only ever a
suggestion, never a guess; the set keys apart from every bottle. The other cases are the
rows a looser rule once joined: a gift set folded into the bottle, a 2 x 1 L pack keyed
as a 2 L bottle. No database: the keying service is fed maps a session would.
"""

from app.services import keying
from app.services.ingest import attributes_disagree
from app.services.normalize import match_key
from tests.test_lines import ONE_MILLION


def key(brand, name, size, *, house="rabanne"):
    return match_key(brand, name, size, vertical="beauty", house=house)


class TestOneMillionUnderOneHouse:
    def test_the_same_bottle_at_two_shops_shares_a_key_whatever_the_wording(self):
        edt_100 = {key(b, n, s) for b, n, s in ONE_MILLION if n in ("Rabanne 1 Million EDT 100ml", "1 Million Eau de Toilette 100 ml")}
        assert edt_100 == {"rabanne|1-million|edt|100ml"}
        elixir_200 = {key(b, n, s) for b, n, s in ONE_MILLION
                      if n in ("1 Million Elixir Parfum Intense 200 ml", "1 Million Elixir Eau de Parfum Intense 200 ml")}
        assert elixir_200 == {"rabanne|1-million|elixir|200ml"}

    def test_an_unknown_variation_keys_apart_and_is_never_guessed(self):
        bare = key("Paco Rabanne", "1 Million 10cl", 100)
        assert bare == "rabanne|1-million||100ml"
        assert bare != key("Paco Rabanne", "1 Million Parfum 10cl", 100) == "rabanne|1-million|parfum|100ml"
        assert bare != key("Rabanne", "Rabanne 1 Million EDT 100ml", 100)

    def test_the_set_never_shares_a_key_with_the_bottle(self):
        assert key("Rabanne", "Rabanne Set: Duo 1 Million Eau de Toilette 50 ml 100 ml", 50) == "rabanne|1-million|edt|50ml+100ml|set"
        assert key("Rabanne", "1 Million Eau de Toilette 50 ml", 50) == "rabanne|1-million|edt|50ml"

    def test_without_the_alias_the_two_houses_key_apart(self):
        assert match_key("Paco Rabanne", "1 Million 10cl", 100, vertical="beauty") == "paco-rabanne|1-million||100ml"
        assert match_key("Rabanne", "1 Million 10cl", 100, vertical="beauty") == "rabanne|1-million||100ml"


class TestTheVeto:
    def test_the_canonical_variation_subsumes_the_parsed_concentration(self):
        assert not attributes_disagree({"concentration": "parfum", "variation": "elixir"},
                                       {"concentration": "edp", "variation": "elixir"})
        assert attributes_disagree({"variation": "edt"}, {"variation": "parfum"})

    def test_without_a_variation_the_concentration_still_vetoes(self):
        assert attributes_disagree({"concentration": "edp"}, {"concentration": "edt"})
        assert not attributes_disagree({"variation": "edt"}, {"concentration": "edt"})


class TestFormsAndDrinks:
    def test_a_gift_set_and_a_pack_key_apart_from_the_bottle(self):
        """A Good Girl gift set (80 ml + 10 ml) was joined to the 8cl bottle; a 2 x 1 L twin
        pack keyed as a 2 L bottle."""
        assert match_key("Carolina Herrera", "Good Girl Gift Set 80ml + 10ml", 90, vertical="beauty").endswith("|set")
        assert match_key("Chivas Regal", "Chivas Regal 12y 40% 2x1L", 2000, vertical="liquor") == "chivas-regal|12||2000ml|pack"
        assert match_key("Chivas Regal", "Chivas Regal 12 Year Old 2L", 2000, vertical="liquor") == "chivas-regal|12||2000ml"

    def test_every_spelling_of_an_age_is_one_key_and_a_drink_has_no_variation(self):
        keys = {match_key("Chivas Regal", n, 1000, vertical="liquor") for n in (
            "Chivas Regal 12 Year Old Blended Scotch Whisky 1L", "Chivas Regal 12 Years Old 1L", "Chivas Regal 12y 40% 1L")}
        assert keys == {"chivas-regal|12||1000ml"}
        assert match_key("Calvin Klein", "Eternity For Men Eau de Toilette 100 ml", 100, vertical="beauty") != \
            match_key("Calvin Klein", "Eternity for Her Eau de Parfum 100 ml", 100, vertical="beauty")


class TestMaps:
    class _Brand:
        def __init__(self, id, slug, canonical_id=None):
            self.id, self.slug, self.canonical_id = id, slug, canonical_id

    def test_the_house_follows_the_alias_and_the_alias_table_wins_over_the_rule(self):
        rabanne, paco = self._Brand(1, "rabanne"), self._Brand(2, "paco-rabanne", canonical_id=1)
        maps = keying.Maps(brands={1: rabanne, 2: paco}, by_slug={"rabanne": rabanne, "paco-rabanne": paco},
                           aliases={("beauty", "elixir parfum intense"): "parfum intense"})
        assert maps.house(2) is rabanne and maps.house(brand="PACO RABANNE") is rabanne
        assert keying.house_words(maps.house(2)) == "rabanne"
        assert maps.variation("1 Million Elixir Parfum Intense 200 ml", "beauty") == "parfum intense"
        assert maps.variation("1 Million Elixir Eau de Parfum Intense 200 ml", "beauty") == "elixir"
        assert maps.variation("Chivas 12", "liquor") == ""
