"""The listings table on /collectors: the tile as the shop showed it, read back from the
fragment the collector kept, beside what we made of it (Stream M, task M1).

The fragments here are real rows from the 11 Sep staging copy, trimmed to the keys the
reader uses. What is pinned: each platform's reader takes the fields from where that
collector took them, an unknown shape yields nothing rather than a guess, and the
"differs" rule treats a spelling as agreement and another brand, another name or another
size as disagreement.
"""

import pytest

from app.services.collector_view import _num, _platform, collected_tile, tile_differs
from app.services.collectors.changi import PRICE_CHANNEL

AVOLTA = {
    "tile": {"sku": "6637902-P::100", "url": "https://buenosaires.shopdutyfree.com/en/54/lancome-genifique-serum-ultimate-50ml",
             "name": "Genifique Serum Ultimate 10cl", "brand": "Lanc\u00f4me", "price": 150.38, "was_price": 200.5},
    "variant": {"price": 150.38, "size_ml": 100, "was_price": 200.5},
    "category_url": "https://buenosaires.shopdutyfree.com/en/54/beauty/skincare",
}
SHOPIFY = {
    "product": {"id": 8632317608128, "title": "N\u00b05", "handle": "n-5", "vendor": "CHANEL",
                "options": [{"name": "Tama\u00f1o", "values": ["100ml"], "position": 1}], "product_type": "Fragancias"},
    "variant": {"id": 48553555722432, "sku": "PCHA105340", "price": "176.00", "title": "100ml", "option1": "100ml",
                "available": True, "compare_at_price": None},
}
ARI = {
    "jsonld": {"mpn": "397595", "sku": "397595", "name": "Perfect Absolute Eau de Parfum 50ml", "@type": "Product",
               "brand": {"name": "Marc  Jacobs", "@type": "Organization"},
               "offers": {"@type": "Offer", "price": "98.5", "availability": "https://schema.org/InStock", "priceCurrency": "EUR"},
               "category": "New In Beauty"},
    "was_price": None,
}
EXTIME = {
    "jsonld": {"name": "Dior Homme Parfum", "@type": "Product", "brand": {"name": "DIOR", "@type": "Brand"},
               "offers": [{"sku": "101380870", "@type": "AggregateOffer", "lowPrice": 97.51, "highPrice": 108.34,
                           "availability": "InStock", "priceCurrency": "EUR"}]},
    "variation": {"id": "106026652", "sku": "101380870", "name": "50 ml", "stock": 305, "capacity": 50, "capacity_unit": "ml",
                  "duty_free": {"price": 97.51, "price_crossed": 108.34, "price_per_quantity": 195.02},
                  "duty_paid": {"price": 97.49, "price_crossed": 130}, "product_name": "Dior Homme Parfum"},
    "main_offer": {"brand_name": "DIOR"},
}
SHILLA = {
    "name": "Moisture Surge\u2122 Intense 72H Lipid Replenishing Hydrator", "brand": "CLINIQUE",
    "specs": {"Weight,Volume": "75ML/2.5OZ"}, "tiers": {"list": 40.0, "member": None, "discount": None},
    "hidden": {"prdPriceDollar": "28.0", "prdPriceWon": "4324.04", "productCode": "4802935"},
    "ref_no": "KPR901", "sku_no": "001510000493", "product_code": "4802935",
}
CHANGI = {
    "code": "mp00201029", "name": "Elizabeth Arden White Tea Wild Rose Pure Indulgence Body Cream 400ml",
    "brandName": "ELIZABETH ARDEN",
    "variant": {"code": "mp00201030", "variantOptionQualifiers": [{"name": "Level1 Sale Measure", "value": "400ml", "qualifier": "level1saleMeasure"}]},
    "offer": {"code": "offer_228355", "channelPrices": [
        {"channelCode": "HOMEDELIVERYTRAVELLER", "enDiscountedPrice": "S$44.95", "enDiscountedValue": "44.95", "enOriginalValue": "44.95"},
        {"channelCode": PRICE_CHANNEL, "enDiscountedPrice": "S$39.95", "enDiscountedValue": "39.95", "enOriginalValue": "44.95"},
    ]},
}
DUBAI = {"id": "123", "displayName": "Johnnie Walker Blue Label 1L", "brand": "Johnnie Walker",
         "salePrice": 180.0, "listPrice": 200.0, "x_gTIN": "5000267014203"}
HEINEMANN = {"code": "8899", "name": "Glenfiddich 12 Years", "brand": "Glenfiddich", "price": {"value": 39.9},
             "strikethroughPrice": {"value": 45.0}, "contentUnit": {"quantity": 0.7, "unit": {"code": "L"}}}


class TestPlatform:
    def test_the_versioned_prefix_names_the_platform(self):
        assert _platform("avolta/2026-09-05") == "avolta"
        assert _platform("heinemann-platform/2026-09-04") == "heinemann"
        assert _platform("heinemann/2026-09-04") == "heinemann"

    def test_a_bare_collector_slug_resolves_through_the_registry(self):
        assert _platform("avolta-zrh") == "avolta"
        assert _platform("iceland-duty-free") == "heinemann"
        assert _platform(None) == ""


class TestCollectedTile:
    def test_avolta_reads_the_tile_and_the_variant(self):
        tile = collected_tile("avolta/2026-09-05", AVOLTA, currency="USD")
        assert tile == {"name": "Genifique Serum Ultimate 10cl", "brand": "Lanc\u00f4me", "size": "10 cl",
                        "size_ml": 100, "price": 150.38, "was_price": 200.5, "currency": "USD"}

    def test_shopify_reads_the_product_and_the_variant(self):
        tile = collected_tile("shopify/2026-09-05", SHOPIFY, currency="USD")
        assert tile["brand"] == "CHANEL" and tile["name"] == "N\u00b05"
        assert (tile["size"], tile["size_ml"], tile["price"], tile["was_price"]) == ("100 ml", 100, 176.0, None)

    def test_ari_reads_the_jsonld_and_declares_its_currency(self):
        tile = collected_tile("ari/2026-09-05", ARI, currency="XXX")
        assert tile["brand"] == "Marc  Jacobs" and tile["price"] == 98.5 and tile["currency"] == "EUR"
        assert (tile["size"], tile["size_ml"]) == ("50 ml", 50)

    def test_extime_reads_the_variation_and_its_duty_free_tier(self):
        tile = collected_tile("extime/2026-09-05", EXTIME)
        assert tile == {"name": "Dior Homme Parfum", "brand": "DIOR", "size": "50 ml", "size_ml": 50,
                        "price": 97.51, "was_price": 108.34, "currency": "EUR"}

    def test_shilla_reads_the_dollar_price_and_the_stated_volume(self):
        tile = collected_tile("shilla/2026-09-05", SHILLA)
        assert tile["brand"] == "CLINIQUE" and tile["currency"] == "USD"
        assert (tile["price"], tile["was_price"]) == (28.0, 40.0)
        assert (tile["size"], tile["size_ml"]) == ("75ML/2.5OZ", 75)

    def test_changi_reads_the_collectors_channel_and_the_sale_measure(self):
        tile = collected_tile("changi/2026-09-05", CHANGI)
        assert tile["brand"] == "ELIZABETH ARDEN" and tile["currency"] == "SGD"
        assert (tile["price"], tile["was_price"]) == (39.95, 44.95)
        assert (tile["size"], tile["size_ml"]) == ("400ml", 400)

    def test_dubai_and_heinemann_read_their_items(self):
        dubai = collected_tile("dubai/2026-09-04", DUBAI, currency="AED")
        assert (dubai["brand"], dubai["price"], dubai["was_price"], dubai["size_ml"], dubai["currency"]) == \
            ("Johnnie Walker", 180.0, 200.0, 1000, "AED")
        heinemann = collected_tile("heinemann-platform/2026-09-04", HEINEMANN, currency="EUR")
        assert (heinemann["size"], heinemann["size_ml"], heinemann["price"], heinemann["was_price"]) == \
            ("0.7 l", 700, 39.9, 45.0)

    def test_entities_are_decoded_as_ingest_decodes_them(self):
        """Dublin's JSON-LD ships "B&amp;G"; the product row holds "B&G". Compared raw, every
        such listed_brand read as another brand."""
        raw = {"jsonld": {"name": "Barton &amp; Guestier Cuvee Speciale White 18.7cl", "brand": {"name": "B&amp;G"},
                          "offers": {"price": "4.25", "priceCurrency": "EUR"}}}
        tile = collected_tile("ari/2026-09-05", raw)
        assert (tile["brand"], tile["name"]) == ("B&G", "Barton & Guestier Cuvee Speciale White 18.7cl")
        assert tile_differs(tile, {"brand": "B&G", "name": "Barton & Guestier Cuvee Speciale White 18.7cl"}) == []

    def test_an_unknown_shape_yields_nothing_rather_than_a_guess(self):
        empty = {"name": None, "brand": None, "size": None, "size_ml": None, "price": None, "was_price": None, "currency": "EUR"}
        assert collected_tile("nope/1", {"name": "x", "price": 3}, currency="EUR") == empty
        assert collected_tile("avolta/2026-09-05", None, currency="EUR") == empty
        assert collected_tile(None, {"tile": {"name": "x"}}, currency="EUR") == empty


class TestNumbers:
    @pytest.mark.parametrize(("raw", "expected"), [
        ("176.00", 176.0), ("1,234.50", 1234.5), ("98,5", 98.5), (12, 12.0), (0.5, 0.5),
        ("", None), (None, None), (True, None), ("n/a", None),
    ])
    def test_a_price_field_in_any_of_its_shapes(self, raw, expected):
        assert _num(raw) == expected


class TestDiffers:
    def test_a_spelling_of_the_house_is_agreement(self):
        assert tile_differs({"brand": "LANCOME"}, {"brand": "Lanc\u00f4me"}) == []
        assert tile_differs({"brand": "Moet & Chandon"}, {"brand": "MOET ET CHANDON"}) == []

    def test_another_house_another_name_another_size_each_differ(self):
        assert tile_differs({"brand": "Paco Rabanne"}, {"brand": "Rabanne"}) == ["brand"]
        assert tile_differs({"name": "1 Million EDT 100ml"}, {"name": "1 Million Eau de Toilette 100 ml"}) == ["name"]
        assert tile_differs({"name": "1 Million 10cl"}, {"name": "1 million  10CL"}) == []
        assert tile_differs({"size_ml": 100}, {"quantity_ml": 50}) == ["size"]
        assert tile_differs({"brand": "Paco Rabanne", "name": "1 Million 10cl", "size_ml": 100}, {"brand": "Rabanne", "name": "1 Million EDT", "quantity_ml": 50}) == ["brand", "name", "size"]

    def test_silence_is_not_a_contradiction(self):
        assert tile_differs({"brand": None, "name": None, "size_ml": None}, {"brand": "Dior", "name": "Sauvage", "quantity_ml": 100}) == []
        assert tile_differs({"brand": "Dior", "size_ml": 100}, {"brand": None, "quantity_ml": None}) == []
