"""
Tests for POST /api/public/contact — Contact Enquiry (INDL-01).
Covers T-01 through T-09 from the PRD test matrix.
"""
import pytest
from httpx import AsyncClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.public.models.website_enquiry import WebsiteEnquiry


CONTACT_URL = "/api/public/contact"

VALID_PAYLOAD = {
    "name": "Jane Doe",
    "email": "jane@cemetery.org",
    "organization": "Greystone Municipal Cemetery",
    "cemetery_type": "Municipal cemetery",
    "message": "Tell us about the platform.",
    "source": "marketing",
}


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

@pytest.mark.asyncio
async def test_contact_happy_path(client: AsyncClient, db_session: AsyncSession):
    """T-01: POST with all valid fields → 201 + row in website_enquiries."""
    response = await client.post(CONTACT_URL, json=VALID_PAYLOAD)
    assert response.status_code == 201
    body = response.json()
    assert body["success"] is True
    assert body["data"]["id"] is not None

    # Verify DB row
    result = await db_session.execute(
        select(WebsiteEnquiry).where(WebsiteEnquiry.email == "jane@cemetery.org")
    )
    enquiry = result.scalar_one_or_none()
    assert enquiry is not None
    assert enquiry.name == "Jane Doe"
    assert enquiry.status == "new"
    assert enquiry.source == "marketing"


# ── T-02: Missing name ───────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_contact_missing_name(client: AsyncClient):
    """T-02: POST without name → 422."""
    payload = {**VALID_PAYLOAD, "name": ""}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 422


@pytest.mark.asyncio
async def test_contact_absent_name(client: AsyncClient):
    """T-02: POST without name field → 422."""
    payload = {k: v for k, v in VALID_PAYLOAD.items() if k != "name"}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 422


# ── T-03: Invalid email format ───────────────────────────────────────────────

@pytest.mark.asyncio
async def test_contact_invalid_email(client: AsyncClient):
    """T-03: POST with invalid email → 422."""
    payload = {**VALID_PAYLOAD, "email": "not-an-email"}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 422


# ── T-04: Message exceeds 5000 characters ───────────────────────────────────

@pytest.mark.asyncio
async def test_contact_message_too_long(client: AsyncClient):
    """T-04: POST with message > 5000 chars → 422."""
    payload = {**VALID_PAYLOAD, "message": "x" * 5001}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 422


# ── T-05: Honeypot field populated ──────────────────────────────────────────

@pytest.mark.asyncio
async def test_contact_honeypot_silently_discarded(client: AsyncClient, db_session: AsyncSession):
    """T-05: POST with honeypot 'website' field → 201 returned, NO DB row."""
    unique_email = "bot+honeypot@spam.example"
    payload = {**VALID_PAYLOAD, "email": unique_email, "website": "http://spam.com"}
    response = await client.post(CONTACT_URL, json=payload)
    # Should look like success to the bot
    assert response.status_code == 201

    # But no DB row should be created
    result = await db_session.execute(
        select(WebsiteEnquiry).where(WebsiteEnquiry.email == unique_email)
    )
    enquiry = result.scalar_one_or_none()
    assert enquiry is None


# ── T-06: SQL injection attempt ──────────────────────────────────────────────

@pytest.mark.asyncio
async def test_contact_sql_injection_safe(client: AsyncClient, db_session: AsyncSession):
    """T-06: SQL injection in name → persisted safely, no DB error."""
    malicious_name = "'; DROP TABLE website_enquiries; --"
    unique_email = "sqlinject@example.org"
    payload = {**VALID_PAYLOAD, "name": malicious_name, "email": unique_email}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 201

    result = await db_session.execute(
        select(WebsiteEnquiry).where(WebsiteEnquiry.email == unique_email)
    )
    enquiry = result.scalar_one_or_none()
    assert enquiry is not None
    assert enquiry.name == malicious_name


# ── T-07: IP address and user agent captured ─────────────────────────────────

@pytest.mark.asyncio
async def test_contact_ip_and_ua_captured(client: AsyncClient, db_session: AsyncSession):
    """T-07: ip_address and user_agent stored from request headers."""
    unique_email = "ua+test@example.org"
    payload = {**VALID_PAYLOAD, "email": unique_email}
    response = await client.post(
        CONTACT_URL,
        json=payload,
        headers={"User-Agent": "TestBot/1.0"},
    )
    assert response.status_code == 201

    result = await db_session.execute(
        select(WebsiteEnquiry).where(WebsiteEnquiry.email == unique_email)
    )
    enquiry = result.scalar_one_or_none()
    assert enquiry is not None
    assert enquiry.user_agent == "TestBot/1.0"


# ── T-08: Custom source value ────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_contact_custom_source(client: AsyncClient, db_session: AsyncSession):
    """T-08: POST with source='pricing-page' → stored correctly."""
    unique_email = "pricing+source@example.org"
    payload = {**VALID_PAYLOAD, "email": unique_email, "source": "pricing-page"}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 201

    result = await db_session.execute(
        select(WebsiteEnquiry).where(WebsiteEnquiry.email == unique_email)
    )
    enquiry = result.scalar_one_or_none()
    assert enquiry is not None
    assert enquiry.source == "pricing-page"


# ── T-09: Name exceeds 255 characters ───────────────────────────────────────

@pytest.mark.asyncio
async def test_contact_name_too_long(client: AsyncClient):
    """T-09 (additional): name > 255 chars → 422."""
    payload = {**VALID_PAYLOAD, "name": "A" * 256}
    response = await client.post(CONTACT_URL, json=payload)
    assert response.status_code == 422


# ── Additional: minimal required fields only ─────────────────────────────────

@pytest.mark.asyncio
async def test_contact_minimal_fields(client: AsyncClient, db_session: AsyncSession):
    """POST with only required fields (name + email) → 201."""
    unique_email = "minimal@example.org"
    response = await client.post(
        CONTACT_URL,
        json={"name": "Minimal User", "email": unique_email},
    )
    assert response.status_code == 201

    result = await db_session.execute(
        select(WebsiteEnquiry).where(WebsiteEnquiry.email == unique_email)
    )
    enquiry = result.scalar_one_or_none()
    assert enquiry is not None
    assert enquiry.organization is None
    assert enquiry.message is None
    assert enquiry.source == "marketing"  # default
