"""
Tests for POST /api/public/inquiries (INDL-24).
Covers T-01 through T-12 from the PRD test matrix.
"""
import pytest
from httpx import AsyncClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.sales.models.contact_inquiry import ContactInquiry


@pytest.fixture(autouse=True)
def clear_rate_limit():
    """Clear all Redis rate limit counters before each test to prevent bleed."""
    import redis
    from src.core.config import settings
    r = redis.from_url(settings.REDIS_URL, decode_responses=True)
    for key in r.keys("rate:cemetery-contact:*"):
        r.delete(key)
    yield
    r.close()


INQUIRY_URL = "/api/public/inquiries"

VALID_PAYLOAD = {
    "topic": "pre_need_plot",
    "sender_name": "Sophie Lavoie",
    "sender_email": "sophie.lavoie@example.ca",
    "sender_phone": "(613) 555-0100",
    "person_or_plot": "plot D-32",
    "message": "I'm interested in purchasing a pre-need plot for my husband and myself in Section D.",
    "subscribe_newsletter": True,
    "website": "",
}


# ── T-01: Happy path ─────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_happy_path(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    """T-01: POST with all valid fields → 201; row in contact_inquiries with status='new'."""
    response = await client.post(
        INQUIRY_URL,
        json=VALID_PAYLOAD,
        headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 201
    body = response.json()
    assert body["success"] is True
    assert body["data"]["reference_id"].startswith("INQ-")

    result = await db_session.execute(
        select(ContactInquiry).where(ContactInquiry.sender_email == "sophie.lavoie@example.ca")
    )
    inq = result.scalar_one_or_none()
    assert inq is not None
    assert inq.source_type == "contact_form"
    assert inq.topic == "pre_need_plot"
    assert inq.person_or_plot == "plot D-32"
    assert inq.subscribe_newsletter is True
    assert inq.status == "new"


# ── T-02: Missing topic ──────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_missing_topic(client: AsyncClient, test_account):
    payload = {k: v for k, v in VALID_PAYLOAD.items() if k != "topic"}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 422


# ── T-03: sender_name empty ───────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_empty_name(client: AsyncClient, test_account):
    payload = {**VALID_PAYLOAD, "sender_name": ""}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 422


# ── T-04: Invalid sender_email ────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_invalid_email(client: AsyncClient, test_account):
    payload = {**VALID_PAYLOAD, "sender_email": "not-an-email"}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 422


# ── T-05: Invalid sender_phone ────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_invalid_phone(client: AsyncClient, test_account):
    payload = {**VALID_PAYLOAD, "sender_phone": "not-a-phone"}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 422


# ── T-06: sender_phone omitted ─────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_phone_omitted(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    payload = {k: v for k, v in VALID_PAYLOAD.items() if k != "sender_phone"}
    payload["sender_email"] = "no.phone@example.ca"
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 201
    result = await db_session.execute(
        select(ContactInquiry).where(ContactInquiry.sender_email == "no.phone@example.ca")
    )
    inq = result.scalar_one_or_none()
    assert inq is not None
    assert inq.sender_phone is None


# ── T-07: message too short ───────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_message_too_short(client: AsyncClient, test_account):
    payload = {**VALID_PAYLOAD, "message": "Hi"}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 422


# ── T-08: message too long ────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_message_too_long(client: AsyncClient, test_account):
    payload = {**VALID_PAYLOAD, "message": "x" * 5001}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 422


# ── T-09: Honeypot ─────────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_honeypot(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    payload = {**VALID_PAYLOAD, "website": "bot", "sender_email": "bot.honeypot@example.ca"}
    response = await client.post(
        INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 201
    assert response.json()["data"]["reference_id"] == "INQ-SPAM-0000"

    result = await db_session.execute(
        select(ContactInquiry).where(ContactInquiry.sender_email == "bot.honeypot@example.ca")
    )
    assert result.scalar_one_or_none() is None


# ── T-10: IP and user-agent captured ──────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_ip_ua_captured(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    payload = {**VALID_PAYLOAD, "sender_email": "ip.ua.cemetery@example.ca"}
    response = await client.post(
        INQUIRY_URL,
        json=payload,
        headers={"X-Tenant-ID": str(test_account.id), "User-Agent": "TestContact/1.0"},
    )
    assert response.status_code == 201
    result = await db_session.execute(
        select(ContactInquiry).where(ContactInquiry.sender_email == "ip.ua.cemetery@example.ca")
    )
    inq = result.scalar_one_or_none()
    assert inq is not None
    assert inq.user_agent == "TestContact/1.0"


# ── T-11: No tenant context ───────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_no_tenant(client: AsyncClient):
    response = await client.post(INQUIRY_URL, json=VALID_PAYLOAD)
    assert response.status_code == 404


# ── T-12: Rate limit (Redis-dependent) ────────────────────────────────────────

@pytest.mark.asyncio
async def test_cemetery_inquiry_rate_limit_eventually_429(
    client: AsyncClient, test_account
):
    statuses = []
    for i in range(6):
        r = await client.post(
            INQUIRY_URL,
            json={**VALID_PAYLOAD, "sender_email": f"ratelimit.cemetery{i}@example.ca"},
            headers={"X-Tenant-ID": str(test_account.id)},
        )
        statuses.append(r.status_code)
    assert all(s in (201, 429) for s in statuses)
