"""The product line page's head (Stream K5; plan W1, W18). What it cost before: every generated page
said `noindex, nofollow`, so a crawler stopped at a page it should have walked through to the indexed
ones, and each `?variant` view would have been a duplicate page without one canonical. No database:
the detail object is built here, the same one the API hands the SPA."""
from __future__ import annotations

from datetime import UTC, datetime, timedelta

from app.models.schemas import (LineAirportOut, LineAttributeOut, LineOptionOut, LinePriceBlockOut, LineSelectorOut, LineVariantOut,
                                PriceOut, ProductLineDetail)
from app.services import catalog_queries, seo

NOW = datetime(2026, 9, 17, 8, 0, tzinfo=UTC)
SHELL = ("<!doctype html><html><head><title>x</title>"
         '<meta name="description" content="old" /></head>'
         '<body><div id="root"></div></body></html>')


def line_price(iata: str, price: float, usd: float, currency: str = "GBP", **over) -> PriceOut:
    city = {"LHR": "London", "CDG": "Paris", "SIN": "Singapore"}.get(iata)
    base = dict(shop_code=f"{iata}1", shop_name=f"{city} shop" if city else "The Catalogue", shop_iata=iata, shop_city=city,
                shop_path={"LHR": "/airports/heathrow-lhr-london", "CDG": "/airports/paris-cdg",
                           "SIN": "/airports/changi-sin-singapore"}.get(iata),
                retailer_name="World Duty Free", is_catalogue_only=False, currency=currency, price=price, price_usd=usd,
                price_type="duty_free", in_stock=True, observed_at=NOW - timedelta(days=1), url=f"https://shop.example/{iata}")
    base.update(over)
    return PriceOut(**base)


def line_variants() -> list[LineVariantOut]:
    def attrs(ml: int, concentration: str) -> list[LineAttributeOut]:
        return [LineAttributeOut(kind="quantity", label="Quantity", text=f"{ml} ml", display="picked"),
                LineAttributeOut(kind="concentration", label="Concentration", text=concentration, display="picked")]

    return [
        LineVariantOut(id=101, name="1 Million Eau de Toilette 100 ml", gtin="3349668508587", quantity_ml=100,
                       attributes=attrs(100, "eau de toilette"), units=2, comparable=True, airports=["CDG", "LHR"],
                       image_url="https://img.example/101.jpg",
                       prices=[line_price("LHR", 80, 101.0), line_price("CDG", 95, 104.0, "EUR")]),
        LineVariantOut(id=102, name="1 Million Elixir 100 ml", quantity_ml=100, attributes=attrs(100, "elixir"), units=2,
                       comparable=True, airports=["CDG", "LHR"],
                       prices=[line_price("CDG", 120, 131.0, "EUR"), line_price("LHR", 110, 139.0)]),
        LineVariantOut(id=103, name="1 Million Parfum 50 ml", quantity_ml=50, attributes=attrs(50, "parfum"), units=1,
                       comparable=False, airports=["SIN"],
                       prices=[line_price("SIN", 150, 112.0, "SGD"),
                               line_price(None, 70, 76.0, "EUR", shop_code="ONLINE", is_catalogue_only=True, shop_path=None)]),
    ]


def line_detail(variant_id: int | None = None, airports: list[str] | None = None, **over) -> ProductLineDetail:
    variants = line_variants()
    chosen = variant_id if variant_id in {v.id for v in variants} else None
    base = dict(
        id=1, slug="rabanne-1-million", name="1 Million", path="/products/rabanne-1-million", brand="Rabanne",
        brand_slug="rabanne", category="Perfume", indexed=False, variants=variants,
        selectors=[LineSelectorOut(kind="quantity", label="Quantity", options=[LineOptionOut(text="100 ml", variant_ids=[101, 102]),
                                                                               LineOptionOut(text="50 ml", variant_ids=[103])])],
        shown=[], chosen_variant_id=chosen, representative_variant_id=catalog_queries.representative_variant(variants),
        airports=list(airports or []), price_block=catalog_queries.price_block(variants, chosen, list(airports or [])),
        last_observed_at=NOW - timedelta(days=1),
    )
    base.update(over)
    return ProductLineDetail(**base)


def test_every_view_is_noindex_follow_with_the_bare_line_as_its_canonical():
    for variant, airports in ((None, []), (101, []), (101, ["LHR", "CDG"])):
        page = seo.head_for_line(line_detail(variant, airports)).apply(SHELL, "https://s.example")
        assert '<meta name="robots" content="noindex, follow" />' in page
        assert '<link rel="canonical" href="https://s.example/products/rabanne-1-million" />' in page


def test_an_indexed_line_carries_no_robots_line():
    page = seo.head_for_line(line_detail(indexed=True)).apply(SHELL, "https://s.example")
    assert 'name="robots"' not in page


def test_the_title_says_the_brand_once_and_never_a_from_price():
    head = seo.head_for_line(line_detail())
    assert head.title.startswith("Rabanne 1 Million: duty-free prices at 3 airports")
    assert seo.head_for_line(line_detail(name="Rabanne 1 Million")).title.startswith("Rabanne 1 Million:")
    assert "From" not in head.title + head.description and "$" not in head.description


def test_the_seed_is_the_detail_under_its_own_key():
    head = seo.head_for_line(line_detail(101, ["LHR"]))
    assert head.seed_key == "__DFP_LINE__" and head.seed["price_block"]["case"] == "chosen_airports"


def _jsonld(page: str) -> list[dict]:
    import json
    import re

    return [json.loads(m) for m in re.findall(r'<script type="application/ld\+json">(.*?)</script>', page, re.S)]


def test_the_group_lists_every_variant_with_its_dated_offers_and_chooses_none():
    """Plan W20: a crawler sees every offer with its shop and date and no chosen price: no aggregate,
    no low or high price, no catalogue offer (a catalogue never prices a page)."""
    page = seo.head_for_line(line_detail()).apply(SHELL, "https://s.example")
    group, crumbs = _jsonld(page)
    assert group["@type"] == "ProductGroup" and group["name"] == "Rabanne 1 Million" and group["productGroupID"] == "rabanne-1-million"
    assert group["url"] == "https://s.example/products/rabanne-1-million" and group["variesBy"] == ["https://schema.org/size"]
    variants = {v["name"]: v for v in group["hasVariant"]}
    assert len(variants) == 3
    edt = variants["1 Million Eau de Toilette 100 ml"]
    assert edt["url"] == "https://s.example/products/rabanne-1-million?variant=101" and edt["gtin13"] == "3349668508587"
    assert edt["size"] == "100 ml"
    assert [(o["price"], o["priceCurrency"], o["validFrom"]) for o in edt["offers"]] == [("80.00", "GBP", "2026-09-16"), ("95.00", "EUR", "2026-09-16")]
    parfum = variants["1 Million Parfum 50 ml"]
    assert [o["availableAtOrFrom"]["name"] for o in parfum["offers"]] == ["Singapore shop (SIN)"]
    text = page.split('<div id="root">', 1)[0]
    for word in ("AggregateOffer", "lowPrice", "highPrice"):
        assert word not in text
    assert crumbs["@type"] == "BreadcrumbList" and crumbs["itemListElement"][-1]["name"] == "Rabanne 1 Million"


def test_the_crawlers_view_asks_for_a_variant_and_links_every_one():
    body = seo.line_body(line_detail(), now=NOW)
    assert '<h1 class="product-title">Rabanne 1 Million</h1>' in body
    assert "Choose a quantity to see its prices." in body and "$" not in body.split("Every variant")[0].split("product-body")[1]
    for vid in (101, 102, 103):
        assert f'href="/products/rabanne-1-million?variant={vid}"' in body


def test_the_body_prints_each_case_as_the_page_does():
    assert "Sold at 2 airports we track" in seo.line_body(line_detail(102), now=NOW)
    one = seo.line_body(line_detail(103), now=NOW)
    assert "Sold at one place we track" in one and "150" in one
    assert "The Catalogue" not in one
    mine = seo.line_body(line_detail(101, ["LHR", "SIN"]), now=NOW)
    assert "Price at LHR, SIN" in mine and "Not stocked at SIN" in mine and "£80.00" in mine
    none = seo.line_body(line_detail(103, ["LHR"]), now=NOW)
    assert "Not stocked at LHR" in none and 'href="/airports/changi-sin-singapore">SIN</a>' in none
    for text in (mine, none, one):
        assert "From $" not in text and "—" not in text
