"""The preview model (task 3.5, design D3, D5, spec link-preview).

Pure tests. The model is a function of an event, its wedding and the published card's
config, so none of this needs a database — which is the point of building it in one place
rather than at each of the three surfaces that render it.

The load-bearing assertion is `test_two_guests_of_one_event_share_a_preview`. Everything
else here is a detail; that one is the property the tokenized route's safety rests on.
"""

import uuid
from datetime import UTC, datetime

from app.models.enums import EventType, Locale
from app.models.wedding import Event, Wedding
from app.services import link_preview

BASE = "https://wedding.example.com"


def _wedding(**overrides: object) -> Wedding:
    wedding = Wedding(
        id=uuid.uuid4(),
        bride_name="Nazifa",
        groom_name="Abdullah",
        slug="nazifa-abdullah",
        default_locale=Locale.EN,
        timezone="Asia/Dhaka",
    )
    for key, value in overrides.items():
        setattr(wedding, key, value)
    return wedding


def _event(**overrides: object) -> Event:
    event = Event(
        id=uuid.uuid4(),
        type=EventType.MARRIAGE,
        slug="marriage",
        title_bn="বিবাহ",
        title_en="Marriage Ceremony",
        # 19:30 in Dhaka (UTC+6), written as UTC because that is how it is stored.
        starts_at=datetime(2026, 12, 12, 13, 30, tzinfo=UTC),
        venue_name="Dhaka Club",
        venue_address="Ramna, Dhaka",
        host_name_1="Abdul Karim",
        host_phone="+8801711223344",
    )
    for key, value in overrides.items():
        setattr(event, key, value)
    return event


def _config(url: str = "/media/cards/e/abc123.png") -> dict[str, object]:
    return {
        "preview_image": {
            "url": url,
            "width": 1200,
            "height": 630,
            "byte_size": 120_000,
            "content_type": "image/png",
        }
    }


# ------------------------------------------------------------------ the guest-free preview


def test_the_preview_names_the_occasion_and_the_couple() -> None:
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE)
    assert preview.title == "Marriage Ceremony — Nazifa & Abdullah"


def test_the_description_carries_the_local_date_and_the_venue() -> None:
    """Stored UTC, read in Dhaka: 13:30Z is a 7:30 PM ceremony, not a 1:30 PM one."""
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE)
    assert "Saturday, 12 December 2026" in preview.description
    assert "7:30 PM" in preview.description
    assert "Dhaka Club" in preview.description


def test_the_canonical_url_is_the_public_page() -> None:
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE)
    assert preview.canonical_url == "https://wedding.example.com/e/marriage"


def test_a_trailing_slash_on_the_base_url_does_not_double_up() -> None:
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE + "/")
    assert preview.canonical_url == "https://wedding.example.com/e/marriage"


def test_the_image_is_absolute_and_carries_its_dimensions() -> None:
    """A crawler resolves a relative URL against nothing, and declares the box from the
    dimensions before the image arrives."""
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE, card_config=_config())
    assert preview.image is not None
    assert preview.image.url == "https://wedding.example.com/media/cards/e/abc123.png"
    assert (preview.image.width, preview.image.height) == (1200, 630)


def test_the_title_follows_the_weddings_locale_not_a_guests() -> None:
    """A per-guest locale would make two guests' meta tags differ, which is exactly the
    property the tokenized route depends on."""
    preview = link_preview.for_event(_event(), _wedding(default_locale=Locale.BN), base_url=BASE)
    assert preview.title.startswith("বিবাহ")


# ------------------------------------------------------------------ degradation


def test_an_event_with_no_published_design_still_previews() -> None:
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE, card_config=None)
    assert preview.image is None
    assert preview.title and preview.description and preview.canonical_url


def test_a_design_published_without_a_picture_previews_without_one() -> None:
    preview = link_preview.for_event(
        _event(), _wedding(), base_url=BASE, card_config={"document": "<div/>"}
    )
    assert preview.image is None


def test_a_malformed_stored_image_reads_as_absent_rather_than_raising() -> None:
    """A broken config must not take the invitation page down with it."""
    preview = link_preview.for_event(
        _event(), _wedding(), base_url=BASE, card_config={"preview_image": {"url": "/x.png"}}
    )
    assert preview.image is None


# ------------------------------------------------------------------ the guest-free property


def test_two_guests_of_one_event_share_a_preview() -> None:
    """The whole basis for putting meta tags on a tokenized URL: what a crawler fetches from
    `/i/{token}` has to be worth no more than what it could fetch from `/e/{slug}`."""
    event, wedding = _event(), _wedding()
    first = link_preview.for_event(event, wedding, base_url=BASE, card_config=_config())
    second = link_preview.for_event(event, wedding, base_url=BASE, card_config=_config())
    assert first == second
    assert first.guest_name is None


def test_no_guest_detail_can_reach_the_guest_free_preview() -> None:
    preview = link_preview.for_event(_event(), _wedding(), base_url=BASE, card_config=_config())
    rendered = " ".join(
        [preview.title, preview.description, preview.canonical_url, preview.site_name]
        + ([preview.image.url] if preview.image else [])
    )
    for leak in ("Rahim", "+8801", "@example.com", "Xk3", "token"):
        assert leak not in rendered


# ------------------------------------------------------------------ the personalised one


def test_the_guest_variant_differs_only_by_the_name() -> None:
    event, wedding = _event(), _wedding()
    shared = link_preview.for_event(event, wedding, base_url=BASE, card_config=_config())
    mine = link_preview.for_guest(
        event, wedding, guest_name="Rahim Uddin", base_url=BASE, card_config=_config()
    )
    assert mine.guest_name == "Rahim Uddin"
    assert (mine.title, mine.description, mine.image) == (
        shared.title,
        shared.description,
        shared.image,
    )


def test_the_guest_variant_still_canonicalises_to_the_public_page() -> None:
    """The anchor in an email is the guest's own link; the canonical URL is not."""
    preview = link_preview.for_guest(
        _event(), _wedding(), guest_name="Rahim", base_url=BASE, card_config=_config()
    )
    assert preview.canonical_url == "https://wedding.example.com/e/marriage"


def test_an_invitation_url_is_built_from_the_same_base() -> None:
    assert link_preview.invitation_url(BASE, "Xk3mQ7") == "https://wedding.example.com/i/Xk3mQ7"
