"""
Tests for POST /api/public/plot-inquiries (INDL-31).
Covers T-09 through T-13 and security case SEC-02.
"""
import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.public.models.plot_inquiry import PlotInquiry

PLOT_INQUIRY_URL = "/api/public/plot-inquiries"

VALID_PAYLOAD = {
    "plot_ref": "B-58",
    "sender_name": "Sophie Lavoie",
    "sender_email": "sophie@example.ca",
    "sender_phone": "(613) 555-0100",
    "relationship": "Planning for a parent",
    "preferred_contact_time": "Weekday mornings (9 am - 12 pm)",
    "message": "I'd like to learn more about plot B-58 for my mother.",
}


@pytest.fixture(autouse=True)
def clear_rate_limit():
    """Clear the Redis rate-limit counter 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:plot-inquiry:*"):
        r.delete(key)
    yield
    r.close()


@pytest_asyncio.fixture
async def test_plot(db_session: AsyncSession, test_account):
    from src.apps.plots.models.plot import Plot

    plot = Plot(tenant_id=test_account.id, plot_ref="B-58", status="vacant")
    db_session.add(plot)
    await db_session.flush()
    return plot


# ── T-09: happy path ──────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_plot_inquiry_happy_path(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    """T-09: valid payload → 201; row in plot_inquiries; reference_id format INQ-PLOT-{YYYY}-{6char}."""
    response = await client.post(
        PLOT_INQUIRY_URL, json=VALID_PAYLOAD, headers={"X-Tenant-ID": str(test_account.id)}
    )
    assert response.status_code == 201
    body = response.json()
    ref = body["data"]["reference_id"]
    assert ref.startswith("INQ-PLOT-")
    parts = ref.split("-")
    assert len(parts[-1]) == 6

    result = await db_session.execute(
        select(PlotInquiry).where(PlotInquiry.sender_email == "sophie@example.ca")
    )
    inq = result.scalar_one_or_none()
    assert inq is not None
    assert inq.status == "new"


# ── T-10: honeypot ────────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_plot_inquiry_honeypot(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    """T-10: honeypot `website` non-empty → 201 fake reference; no DB row."""
    payload = {**VALID_PAYLOAD, "website": "http://spam.example.com"}
    response = await client.post(
        PLOT_INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)}
    )
    assert response.status_code == 201
    assert response.json()["data"]["id"] is None

    result = await db_session.execute(
        select(PlotInquiry).where(PlotInquiry.sender_email == "sophie@example.ca")
    )
    assert result.scalar_one_or_none() is None


# ── T-11: rate limit ──────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_plot_inquiry_rate_limited(client: AsyncClient, test_account):
    """T-11: 6th submission from the same IP within 1h → 429."""
    headers = {"X-Tenant-ID": str(test_account.id)}
    for _ in range(5):
        response = await client.post(PLOT_INQUIRY_URL, json=VALID_PAYLOAD, headers=headers)
        assert response.status_code == 201

    response = await client.post(PLOT_INQUIRY_URL, json=VALID_PAYLOAD, headers=headers)
    assert response.status_code == 429


# ── T-12: missing contact method ──────────────────────────────────────────────

@pytest.mark.asyncio
async def test_plot_inquiry_missing_contact_method(client: AsyncClient, test_account):
    """T-12: missing both email and phone → 422."""
    payload = {k: v for k, v in VALID_PAYLOAD.items() if k not in ("sender_email", "sender_phone")}
    response = await client.post(
        PLOT_INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)}
    )
    assert response.status_code == 422


# ── T-13: no tenant context ───────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_plot_inquiry_no_tenant(client: AsyncClient):
    """T-13: no tenant context → 404."""
    response = await client.post(PLOT_INQUIRY_URL, json=VALID_PAYLOAD)
    assert response.status_code == 404


# ── SEC-02: cross-tenant plot_id rejected ─────────────────────────────────────

@pytest.mark.asyncio
async def test_plot_inquiry_cross_tenant_plot_id_rejected(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    """SEC-02: plot_id belonging to a different tenant → 422."""
    from src.apps.tenants.models.account import Account
    from src.apps.plots.models.plot import Plot

    other = Account(
        organization_name="Other Cemetery", subdomain="othercemetery2",
        contact_email="admin@othercemetery2.com", plan="starter", status="active",
    )
    db_session.add(other)
    await db_session.flush()

    other_plot = Plot(tenant_id=other.id, plot_ref="X-99", status="vacant")
    db_session.add(other_plot)
    await db_session.flush()

    payload = {**VALID_PAYLOAD, "plot_id": str(other_plot.id)}
    response = await client.post(
        PLOT_INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)}
    )
    assert response.status_code == 422


@pytest.mark.asyncio
async def test_plot_inquiry_valid_plot_id_same_tenant(
    client: AsyncClient, test_plot, test_account
):
    payload = {**VALID_PAYLOAD, "plot_id": str(test_plot.id)}
    response = await client.post(
        PLOT_INQUIRY_URL, json=payload, headers={"X-Tenant-ID": str(test_account.id)}
    )
    assert response.status_code == 201
