"""`GET /api/airports/{iata}/hours` and the provenance the page carries (Stream G, G3).

No database: the store and the shop lookup are stubbed. What it pins: the three answers
(collected, hand, none), a hidden or unknown airport as a 404 like its page, the route in the
storefront's open class, and the guide's provenance fields filled from a row.
"""

from datetime import UTC, datetime
from types import SimpleNamespace

from fastapi import FastAPI
from fastapi.testclient import TestClient

from app.db import get_db
from app.models.hubs import AirportGuide, HoursProvenance
from app.routers import airports
from app.services import access, airport_guides, catalog_queries
from app.services.hours import store

WHEN = datetime(2026, 9, 11, 22, 0, tzinfo=UTC)


def row(kind: str, **over):
    base = dict(source_kind=kind, text="World Duty Free, 14 stores", observed_at=WHEN,
                source_url="https://www.heathrow.com/at-the-airport/shops-a-z/world-duty-free" if kind == "collected" else None,
                entered_by_id=1 if kind == "hand" else None)
    base.update(over)
    return SimpleNamespace(**base)


def client(monkeypatch, current, username="rian"):
    monkeypatch.setattr(catalog_queries, "airport_shops", lambda db, iata=None: ["a shop"] if iata in ("LHR", "DUB") else [])
    monkeypatch.setattr(store, "current_for_airport", lambda db, iata: current.get(iata))
    monkeypatch.setattr(store, "entered_by_username", lambda db, r: username if r.entered_by_id else None)
    api = FastAPI()
    api.include_router(airports.router)
    api.dependency_overrides[get_db] = lambda: iter([None])
    return TestClient(api)


class TestRoute:
    def test_collected_hand_and_none(self, monkeypatch):
        c = client(monkeypatch, {"LHR": row("collected"), "DUB": row("hand", text="T1 04:00-22:00")})
        assert c.get("/api/airports/LHR/hours").json() == {
            "kind": "collected", "text": "World Duty Free, 14 stores", "observed_at": "2026-09-11T22:00:00Z",
            "entered_by_username": None,
            "source_url": "https://www.heathrow.com/at-the-airport/shops-a-z/world-duty-free",
        }
        assert c.get("/api/airports/dub/hours").json() == {
            "kind": "hand", "text": "T1 04:00-22:00", "observed_at": "2026-09-11T22:00:00Z",
            "entered_by_username": "rian", "source_url": None,
        }

    def test_nothing_at_all_where_neither_exists(self, monkeypatch):
        c = client(monkeypatch, {})
        assert c.get("/api/airports/LHR/hours").json() == {
            "kind": "none", "text": None, "observed_at": None, "entered_by_username": None, "source_url": None,
        }

    def test_a_hidden_or_unknown_airport_is_a_404_like_its_page(self, monkeypatch):
        c = client(monkeypatch, {"ATH": row("hand")})
        assert c.get("/api/airports/ATH/hours").status_code == 404  # no visible shop: hidden
        assert c.get("/api/airports/london/hours").status_code == 404

    def test_the_route_is_a_storefront_read(self):
        assert access.classify("GET /api/airports/{iata}/hours") == ("public_when_open", None)


class TestGuideProvenance:
    def test_the_guide_carries_the_provenance_beside_the_hours(self, monkeypatch):
        monkeypatch.setattr(store, "current_for_airport", lambda db, iata: row("collected"))
        monkeypatch.setattr(store, "entered_by_username", lambda db, r: None)
        guide = airport_guides.guide_for("LHR", db=object())
        assert guide.hours == "World Duty Free, 14 stores"
        assert guide.hours_provenance == HoursProvenance(
            kind="collected", observed_at=WHEN, entered_by_username=None,
            source_url="https://www.heathrow.com/at-the-airport/shops-a-z/world-duty-free", source_host="www.heathrow.com",
        )
        assert len(guide.terminals) == 4  # the written half is untouched

    def test_a_hand_row_names_the_account_and_no_host(self, monkeypatch):
        monkeypatch.setattr(store, "current_for_airport", lambda db, iata: row("hand"))
        monkeypatch.setattr(store, "entered_by_username", lambda db, r: "adam")
        guide = airport_guides.guide_for("DUB", db=object())
        assert guide == AirportGuide(hours="World Duty Free, 14 stores", hours_provenance=HoursProvenance(
            kind="hand", observed_at=WHEN, entered_by_username="adam", source_url=None, source_host=None))
