"""
Tests for the public "Find a loved one" search (GET /api/public/records):
  - flat paginated response shape (data = list, total/page at root)
  - typo-tolerant (trigram) fuzzy matching
  - memorial_slug exposed only for a published memorial
  - visibility gate (only visibility_config='public')
"""
import pytest
from httpx import AsyncClient

TENANT_HDR = "X-Tenant-ID"


async def _make_public_record(db, tenant_id, *, first, last, visibility="public", with_published_memorial=False):
    from src.apps.records.models.record import Record
    from src.apps.memorials.models.memorial import Memorial

    rec = Record(
        tenant_id=tenant_id, first_name=first, last_name=last, visibility_config=visibility
    )
    db.add(rec)
    await db.flush()
    if with_published_memorial:
        slug = f"{first}-{last}".lower().replace("'", "").replace(" ", "-")
        db.add(Memorial(tenant_id=tenant_id, record_id=rec.id, slug=slug, is_published=True))
        await db.flush()
    return rec


@pytest.mark.asyncio
async def test_search_exposes_plot_coordinates_for_directions(
    client: AsyncClient, db_session, test_account
):
    """INDL-56: a public record linked to a plot with GPS returns lat/lng so a
    search result can offer "Get directions"; a record with no plot returns
    null coords (button disabled client-side)."""
    from src.apps.plots.models.plot import Plot
    from src.apps.records.models.record import Record

    plot = Plot(
        tenant_id=test_account.id, plot_ref="Z-9", status="occupied",
        latitude=45.4221458, longitude=-75.6966031,
    )
    db_session.add(plot)
    await db_session.flush()
    db_session.add(Record(
        tenant_id=test_account.id, first_name="Located", last_name="Person",
        visibility_config="public", plot_id=plot.id,
    ))
    db_session.add(Record(
        tenant_id=test_account.id, first_name="Unplaced", last_name="Person",
        visibility_config="public",
    ))
    await db_session.flush()

    r = await client.get(
        "/api/public/records?name=person", headers={TENANT_HDR: str(test_account.id)}
    )
    assert r.status_code == 200
    by_name = {row["first_name"]: row for row in r.json()["data"]}
    assert by_name["Located"]["latitude"] == pytest.approx(45.4221458)
    assert by_name["Located"]["longitude"] == pytest.approx(-75.6966031)
    assert by_name["Unplaced"]["latitude"] is None
    assert by_name["Unplaced"]["longitude"] is None


@pytest.mark.asyncio
async def test_search_response_is_flat_shape(client: AsyncClient, db_session, test_account):
    await _make_public_record(db_session, test_account.id, first="Patricia", last="OBrien")
    r = await client.get("/api/public/records?name=patricia", headers={TENANT_HDR: str(test_account.id)})
    assert r.status_code == 200
    body = r.json()
    # Flat shape: data is a list, pagination at root (NOT data.items)
    assert isinstance(body["data"], list)
    assert "total" in body and "page" in body and "pages" in body
    assert body["total"] == 1


@pytest.mark.asyncio
async def test_search_is_typo_tolerant(client: AsyncClient, db_session, test_account):
    await _make_public_record(db_session, test_account.id, first="Patricia", last="OBrien")
    # "patrica" is a common misspelling of "Patricia" (not a substring of it)
    r = await client.get("/api/public/records?name=patrica", headers={TENANT_HDR: str(test_account.id)})
    assert r.status_code == 200
    assert r.json()["total"] == 1


@pytest.mark.asyncio
async def test_search_exposes_memorial_slug_when_published(client: AsyncClient, db_session, test_account):
    await _make_public_record(
        db_session, test_account.id, first="Patricia", last="OBrien", with_published_memorial=True
    )
    r = await client.get("/api/public/records?name=patricia", headers={TENANT_HDR: str(test_account.id)})
    item = r.json()["data"][0]
    assert item["memorial_slug"] == "patricia-obrien"


@pytest.mark.asyncio
async def test_search_no_slug_without_memorial(client: AsyncClient, db_session, test_account):
    await _make_public_record(db_session, test_account.id, first="Nomem", last="Orial")
    r = await client.get("/api/public/records?name=nomem", headers={TENANT_HDR: str(test_account.id)})
    assert r.json()["data"][0]["memorial_slug"] is None


@pytest.mark.asyncio
async def test_search_excludes_non_public_records(client: AsyncClient, db_session, test_account):
    await _make_public_record(db_session, test_account.id, first="Hidden", last="Person", visibility="private")
    r = await client.get("/api/public/records?name=hidden", headers={TENANT_HDR: str(test_account.id)})
    assert r.json()["total"] == 0
