"""11F2: booking.appointment App Block on the existing Cloud booking store."""

from pathlib import Path
import json

from src.domain.app_blocks import compiler
from src.domain.app_blocks.catalogs import FEATURE_PACK_ALIASES, default_known_packs
from src.domain.app_blocks.canonical import DUAL_NAMESPACE_IDS, feature_pack_only_aliases
from src.domain.app_blocks.hosts import merge_host_map
from src.domain.app_blocks.planner import ProductIntent, select_capabilities
from src.domain.app_blocks.public import _BLOCK_COPY
from src.domain.app_blocks.registry import load_default_registry

ROOT = Path(__file__).resolve().parents[1]


def test_booking_is_a_block_not_inferred_from_pack_alias():
    registry = load_default_registry()
    assert "booking.appointment" not in feature_pack_only_aliases()
    assert "booking.appointment" in DUAL_NAMESPACE_IDS
    assert FEATURE_PACK_ALIASES["booking.appointment"] == "appointment-booking"
    block = registry.require("booking.appointment")
    assert block.id == "booking.appointment"
    canonical = registry.canonical.require("booking.appointment")
    assert canonical.installation.feature_packs == ("appointment-booking",)
    assert canonical.id != "appointment-booking"
    assert {dep.id for dep in canonical.requires if dep.kind == "primitive"} >= {
        "booking.reserve",
        "booking.cancel",
        "booking.availability",
    }
    assert "data.entity" not in {dep.id for dep in canonical.requires}


def test_planner_matches_appointment_phrases_only():
    hit = select_capabilities(ProductIntent(purpose="Staff can book an appointment"))
    assert any(block_id == "booking.appointment" for _cap, block_id, _reason in hit)
    miss = select_capabilities(ProductIntent(purpose="Add a Google Calendar and hotel booking later"))
    assert not any(block_id == "booking.appointment" for _cap, block_id, _reason in miss)


def test_public_label_does_not_leak_the_raw_id():
    label = _BLOCK_COPY["booking.appointment"]
    assert label == "Appointment booking"
    assert label != "booking.appointment"


def test_install_plan_resolves_appointment_booking_pack(monkeypatch):
    registry = load_default_registry()
    monkeypatch.setattr(
        compiler,
        "select_capabilities",
        lambda _intent: [("booking_appointment", "booking.appointment", "Selected.")],
    )
    plan = compiler.compile_install_plan(None, registry=registry)
    assert not plan.unsatisfiable
    assert plan.required_feature_packs == ["appointment-booking"]
    assert {"booking.reserve", "booking.cancel", "booking.availability"} <= set(plan.required_primitives)
    assert "data.entity" not in plan.required_primitives
    assert "booking.appointment" in {block.id for block in plan.blocks}


def test_missing_pack_is_an_honest_gap_not_a_record_engine_fallback(monkeypatch):
    registry = load_default_registry()
    monkeypatch.setattr(
        compiler,
        "select_capabilities",
        lambda _intent: [("booking_appointment", "booking.appointment", "Selected.")],
    )
    plan = compiler.compile_install_plan(
        None, registry=registry, known_packs=default_known_packs() - {"appointment-booking"}
    )
    assert plan.unsatisfiable
    assert any(gap.id == "appointment-booking" for gap in plan.gaps)


def test_materialized_booking_hosts_submit_through_booking_ports():
    for framework in ("html", "nuxt_app", "react_app"):
        root = ROOT / "boilerplates" / framework
        hosts = merge_host_map(json.loads((root / "p2hs/app-block-hosts.json").read_text()))
        booking = {h["slot"]: h for h in hosts["hosts"] if h["block"] == "booking.appointment"}
        assert {"book", "success", "empty"} <= set(booking)
        book = booking["book"]["implementation"]
        path = book.partition("#")[0]
        source = (root / path).read_text(encoding="utf-8")
        assert "/api/bookings/reserve" in source
        assert "createRecord" not in source
        for slot in ("success", "empty"):
            assert booking[slot]["implementation"]
