"""Raw records and verticals: what every collector must carry back.

Decided 2026-09-04 after confirming nothing of what a collector saw was kept
(`\\d price_observations` had no payload): every rule change meant a re-fetch,
at crawl delays of 30 to 60 seconds a page. Two rules live here. A raw record
must be facts only, because the legal posture (COLLECTORS.md L2) rests on never
ingesting marketing copy or imagery. And a listing names the family it was
found in, so a beauty product is never filed as a drink by default.
"""

import json
from pathlib import Path

from app.services.collectors.ari import listing_from_page
from app.services.collectors.avolta import STORES, AvoltaCollector, parse_product_variants
from app.services.collectors.base import ListingRef, facts_only, listing_ref
from app.services.collectors.extime import Extime
from app.services.collectors.shopify import SHOPS, ShopifyCollector
from app.services.ingest import resolve_vertical
from app.services.taxonomy import vertical_from_hints, vertical_of

FIXTURES = Path(__file__).parent / "fixtures"
EXTIME_PAGE = (FIXTURES / "extime_product.html").read_text()
EXTIME_URL = "https://www.extime.com/en/paris/product/single-malt-whisky-ten-years-old-107222991"


class TestFactsOnly:
    def test_expression_keys_are_dropped_at_any_depth(self):
        """A stored description or image URL hands a plaintiff the copyrighted
        work the price data itself never is."""
        item = {
            "displayName": "Some Whisky",
            "longDescription": "<p>Velvety notes of ...</p>",
            "primaryFullImageURL": "/img/x.jpg",
            "price": {"value": 1, "image": "x"},
            "variants": [{"sku": "1", "featured_image": {"src": "y"}, "body_html": "z"}],
            "seo_title": "buy now",
        }
        kept = facts_only(item)
        assert kept == {"displayName": "Some Whisky", "price": {"value": 1}, "variants": [{"sku": "1"}]}

    def test_shopify_body_html_and_images_never_reach_storage(self):
        product = {"id": 1, "title": "Gin", "vendor": "X", "body_html": "<p>copy</p>",
                   "images": [{"src": "a"}], "image": {"src": "a"}, "product_type": "Gin",
                   "tags": ["gin"], "handle": "gin", "variants": []}
        variant = {"id": 9, "title": "70cl", "price": "20.00", "available": True,
                   "featured_image": {"src": "b"}, "barcode": ""}
        shop, slug, name, op = SHOPS[0]
        row = ShopifyCollector(shop, slug, name, op).listing(product, variant)
        blob = json.dumps(row.raw)
        assert "body_html" not in blob and "images" not in blob and "featured_image" not in blob
        assert row.raw["product"]["title"] == "Gin" and row.raw["variant"]["price"] == "20.00"
        assert "variants" not in row.raw["product"]


class TestVerticals:
    def test_every_category_maps_to_one_family(self):
        assert vertical_of("Whisky") == "liquor"
        assert vertical_of("Perfume") == "beauty"
        assert vertical_of("Confectionery") == "confectionery"
        assert vertical_of(None) is None

    def test_a_retailers_own_tree_name_is_read(self):
        assert vertical_from_hints("https://x/en/1/liquor/whisky") == "liquor"
        assert vertical_from_hints("Beverage") == "liquor"
        assert vertical_from_hints("/beauty/fragrance/") == "beauty"
        assert vertical_from_hints("Gifts") is None

    def test_our_category_beats_the_collectors_claim_beats_the_default(self):
        """A skincare product found on a drinks walk is still beauty."""
        assert resolve_vertical("liquor", "Skincare", None) == "beauty"
        assert resolve_vertical("beauty", None, None) == "beauty"
        assert resolve_vertical(None, None, "tobacco") == "tobacco"
        # A product nothing placed is `unknown`, never "liquor" by default (identity rules v6: it
        # also takes the `n/a` quantity slot when it states none, like the ring from Panama).
        assert resolve_vertical(None, None, None) == "unknown"


class TestCollectorsCarryTheFragment:
    def test_avolta_keeps_the_tile_and_names_the_tree(self):
        html = '''<div class="product-item-info">
          <a class="product-item-link" href="https://x/en/1/p">Some Whisky 1L</a>
          <span data-price-type="finalPrice" data-price-amount="38.23">£38.23</span>
          <span data-product-sku="5000267023625"></span></div>'''
        item = parse_product_variants(html)[0]
        row = AvoltaCollector(STORES[0])._listing(item, "GBP", "https://x/en/1/liquor/whisky", 38.23, None)
        assert row.vertical == "liquor"
        assert row.raw["tile"]["sku"] == "5000267023625" and "html" not in row.raw["tile"]
        assert 'data-price-amount="38.23"' in row.raw["tile_html"]
        assert row.raw["variant"] is None

    def test_extime_keeps_offer_and_variation_and_reads_the_family(self):
        row = Extime()._listings(EXTIME_URL, EXTIME_PAGE)[0]
        assert row.vertical == "liquor"  # categories_name[0] is "Beverage"
        assert row.raw["jsonld"]["@type"] == "Product"
        assert "description" not in row.raw["jsonld"] and "image" not in row.raw["jsonld"]
        assert row.raw["main_offer"]["gtin"] == "5010494195125"
        assert row.raw["variation"]["capacity"] == 100

    def test_ari_keeps_the_jsonld_and_reads_the_path(self):
        page = '''<html><script type="application/ld+json">{"@type": "Product",
          "name": "Redbreast 12 Year Old 70cl", "sku": "12345", "description": "copy",
          "image": "x.jpg", "brand": {"name": "Redbreast"}, "category": "Irish Whiskey",
          "offers": [{"price": "55.00", "priceCurrency": "EUR", "availability": "InStock"},
                     {"price": "72.00", "priceCurrency": "EUR"}]}</script></html>'''
        row = listing_from_page("https://www.dublinandcorkdutyfree.ie/alcohol/irish-whiskey/12345.html", page)
        assert row.price == 55.0 and row.vertical == "liquor"
        assert "description" not in row.raw["jsonld"] and "image" not in row.raw["jsonld"]


class TestListingRef:
    def test_a_database_listing_is_reduced_to_what_a_collector_needs(self):
        class Loc:
            code = "LHR"
        class DbListing:
            source_sku = "123"
            url = "https://x/p"
            shop = Loc()
        assert listing_ref(DbListing()) == ListingRef("123", "https://x/p", "LHR")
        assert listing_ref(ListingRef("1", None, "X")) == ListingRef("1", None, "X")
