"""
Tests for INDL-53 — Marketing Who We Serve Category CMS, public route.

Covers the PRD's "Technical Scope" backend bullet:
  - GET /public/who-we-serve requires no auth
  - returns all 4 fixed categories, ordered by sort_order
  - public shape is data-minimized: only category_key/badge_label/heading/
    intro/points -- no id/sort_order/timestamps
  - order matches the site-admin GET order
  - a site-admin PATCH is reflected on the next public GET (round-trip
    persistence check across the two routers)

The `indelis_test` DB is migration-managed and already seeded (migration
0060) with exactly 4 `who_we_serve_categories` rows. Per
`tests/conftest.py`, `db_session` only ever `flush()`s within a test and
is rolled back in teardown, so writes made here (via the site-admin API,
to stay black-box) never leak into other tests.
"""
import pytest
from uuid import uuid4

from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.auth.models.user import User
from src.core.security import hash_password


async def _site_admin_token(db: AsyncSession) -> str:
    from src.core.security import create_access_token, build_token_payload

    user = User(
        tenant_id=None,
        email=f"sa.pubww.{id(db)}.{uuid4().hex[:8]}@indelis.com",
        password_hash=hash_password("Test1234!"),
        first_name="Site",
        last_name="Admin",
        role="site_admin",
        status="active",
    )
    db.add(user)
    await db.flush()
    return create_access_token(build_token_payload(user))


@pytest.mark.asyncio
async def test_public_who_we_serve_requires_no_auth(
    client: AsyncClient, db_session: AsyncSession
):
    resp = await client.get("/api/public/who-we-serve")
    assert resp.status_code == 200


@pytest.mark.asyncio
async def test_public_who_we_serve_returns_4_categories_minimized_shape(
    client: AsyncClient, db_session: AsyncSession
):
    resp = await client.get("/api/public/who-we-serve")
    assert resp.status_code == 200
    data = resp.json()["data"]

    assert len(data) == 4
    keys = {c["category_key"] for c in data}
    assert keys == {"municipal", "private", "funeral_groups", "religious"}

    for item in data:
        assert set(item.keys()) == {
            "category_key",
            "badge_label",
            "heading",
            "intro",
            "points",
        }


@pytest.mark.asyncio
async def test_public_who_we_serve_order_matches_admin_order(
    client: AsyncClient, db_session: AsyncSession
):
    token = await _site_admin_token(db_session)
    admin_data = (
        await client.get(
            "/api/site-admin/who-we-serve", headers={"Authorization": f"Bearer {token}"}
        )
    ).json()["data"]
    admin_keys_in_order = [c["category_key"] for c in admin_data]

    public_data = (await client.get("/api/public/who-we-serve")).json()["data"]
    public_keys_in_order = [c["category_key"] for c in public_data]

    assert public_keys_in_order == admin_keys_in_order


@pytest.mark.asyncio
async def test_public_who_we_serve_reflects_admin_patch(
    client: AsyncClient, db_session: AsyncSession
):
    token = await _site_admin_token(db_session)
    unique_heading = f"Round trip heading {uuid4().hex[:8]}"

    patch_resp = await client.patch(
        "/api/site-admin/who-we-serve/religious",
        json={
            "heading": unique_heading,
            "intro": "A freshly updated intro paragraph for religious.",
            "points": [
                "Updated point one",
                "Updated point two",
                "Updated point three",
                "Updated point four",
            ],
        },
        headers={"Authorization": f"Bearer {token}"},
    )
    assert patch_resp.status_code == 200

    public_data = (await client.get("/api/public/who-we-serve")).json()["data"]
    religious = next(c for c in public_data if c["category_key"] == "religious")
    assert religious["heading"] == unique_heading
    assert religious["points"] == [
        "Updated point one",
        "Updated point two",
        "Updated point three",
        "Updated point four",
    ]
