"""Collector-layer skips reach the run that consumes them.

A collector that quietly `continue`s past an unpriced or unreadable item
leaves no trace, and the audit could not tell a shop with 40 unpriced items
from a parser that stopped reading prices. The hook is run-scoped and a
no-op outside a run, so collectors stay usable from a shell.
"""

from app.services.collectors.base import bind_skip_sink, report_skip, unbind_skip_sink
from app.services.collectors.shopify import SHOPS, ShopifyCollector


def test_outside_a_run_the_hook_is_silent():
    report_skip("no_price", source_sku="1")  # must not raise


def test_inside_a_run_the_sink_hears_every_skip():
    heard = []
    token = bind_skip_sink(lambda reason, detail: heard.append((reason, detail)))
    try:
        report_skip("no_price", source_sku="1", url="https://x/p")
    finally:
        unbind_skip_sink(token)
    report_skip("no_price", source_sku="2")  # unbound again
    assert heard == [("no_price", {"source_sku": "1", "url": "https://x/p"})]


def test_a_collector_reports_the_variant_it_could_not_price():
    shop, slug, name, op = SHOPS[0]
    collector = ShopifyCollector(shop, slug, name, op)
    assert collector.listing({"title": "Gin", "handle": "gin"}, {"id": 9, "price": "0.00"}) is None
