"""
Tests for POST /api/v1/sales/inquiries/log-email (INDL-25).
Covers T-10 through T-12 and related scenarios from the PRD.
"""
import pytest
from datetime import datetime, timezone, timedelta
from httpx import AsyncClient
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

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


LOG_EMAIL_URL = "/api/v1/sales/inquiries/log-email"

VALID_EMAIL_PAYLOAD = {
    "sender_name": "Priya Mehta",
    "sender_email": "priya.mehta@example.com",
    "email_subject": "Plot enquiry Section B",
    "email_received_at": (datetime.now(timezone.utc) - timedelta(hours=1)).isoformat(),
    "message": "Hello, I'm writing to enquire about available plots in Section B near the east garden.",
}


def _tenant_headers(token: str, tenant_id: str):
    return {
        "Authorization": f"Bearer {token}",
        "X-Tenant-ID": tenant_id,
    }


# ── T-10: Happy path ─────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_log_email_happy_path(
    client: AsyncClient,
    db_session: AsyncSession,
    admin_token: str,
    test_account,
):
    """T-10: POST with valid fields → 201; row with source_type='email'."""
    response = await client.post(
        LOG_EMAIL_URL,
        json=VALID_EMAIL_PAYLOAD,
        headers=_tenant_headers(admin_token, str(test_account.id)),
    )
    assert response.status_code == 201
    body = response.json()
    assert body["success"] is True
    data = body["data"]
    assert data["source_type"] == "email"
    assert data["sender_name"] == "Priya Mehta"
    assert data["sender_email"] == "priya.mehta@example.com"
    assert data["email_subject"] == "Plot enquiry Section B"
    assert data["status"] == "new"

    result = await db_session.execute(
        select(ContactInquiry).where(ContactInquiry.id == data["id"])
    )
    inq = result.scalar_one_or_none()
    assert inq is not None
    assert inq.source_type == "email"
    assert inq.email_subject == "Plot enquiry Section B"
    assert inq.email_received_at is not None


# ── T-11: Unauthenticated → 401 ──────────────────────────────────────────────

@pytest.mark.asyncio
async def test_log_email_unauthenticated(client: AsyncClient, test_account):
    """T-11: Unauthenticated request → 401."""
    response = await client.post(
        LOG_EMAIL_URL,
        json=VALID_EMAIL_PAYLOAD,
        headers={"X-Tenant-ID": str(test_account.id)},
    )
    assert response.status_code == 401


# ── T-12: Email body < 10 chars → 422 ────────────────────────────────────────

@pytest.mark.asyncio
async def test_log_email_body_too_short(
    client: AsyncClient, admin_token: str, test_account
):
    """T-12: message (email body) under 10 chars → 422."""
    payload = {**VALID_EMAIL_PAYLOAD, "message": "Hi there."}
    response = await client.post(
        LOG_EMAIL_URL,
        json=payload,
        headers=_tenant_headers(admin_token, str(test_account.id)),
    )
    assert response.status_code == 422


# ── view_only → 403 ──────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_log_email_view_only_forbidden(
    client: AsyncClient, db_session: AsyncSession, test_account
):
    """log-email by view_only user → 403."""
    from src.apps.auth.models.user import User
    from src.core.security import hash_password, create_access_token, build_token_payload

    view_user = User(
        tenant_id=test_account.id,
        email="view.email@testcemetery.com",
        password_hash=hash_password("Test1234"),
        first_name="View",
        last_name="Email",
        role="view_only",
        status="active",
    )
    db_session.add(view_user)
    await db_session.flush()

    token = create_access_token(build_token_payload(view_user, test_account))
    response = await client.post(
        LOG_EMAIL_URL,
        json=VALID_EMAIL_PAYLOAD,
        headers=_tenant_headers(token, str(test_account.id)),
    )
    assert response.status_code == 403


# ── Future email_received_at → 422 ───────────────────────────────────────────

@pytest.mark.asyncio
async def test_log_email_future_received_at_rejected(
    client: AsyncClient, admin_token: str, test_account
):
    """email_received_at 10 minutes in the future → 422."""
    future = (datetime.now(timezone.utc) + timedelta(minutes=10)).isoformat()
    payload = {**VALID_EMAIL_PAYLOAD, "email_received_at": future}
    response = await client.post(
        LOG_EMAIL_URL,
        json=payload,
        headers=_tenant_headers(admin_token, str(test_account.id)),
    )
    assert response.status_code == 422


# ── Missing email_subject → 422 ──────────────────────────────────────────────

@pytest.mark.asyncio
async def test_log_email_missing_subject(
    client: AsyncClient, admin_token: str, test_account
):
    """Missing email_subject → 422."""
    payload = {k: v for k, v in VALID_EMAIL_PAYLOAD.items() if k != "email_subject"}
    response = await client.post(
        LOG_EMAIL_URL,
        json=payload,
        headers=_tenant_headers(admin_token, str(test_account.id)),
    )
    assert response.status_code == 422


# ── T-13: GET /inquiries returns all source types ────────────────────────────

@pytest.mark.asyncio
async def test_list_inquiries_all_source_types(
    client: AsyncClient,
    db_session: AsyncSession,
    admin_token: str,
    test_account,
):
    """T-13: After logging an email, GET /inquiries returns it with source_type='email'."""
    await client.post(
        LOG_EMAIL_URL,
        json={**VALID_EMAIL_PAYLOAD, "sender_email": "listsource@example.com"},
        headers=_tenant_headers(admin_token, str(test_account.id)),
    )
    list_resp = await client.get(
        "/api/v1/sales/inquiries",
        headers=_tenant_headers(admin_token, str(test_account.id)),
    )
    assert list_resp.status_code == 200
    items = list_resp.json()["data"]
    email_items = [i for i in items if i["source_type"] == "email"]
    assert len(email_items) >= 1
    # Source-irrelevant fields are null for email cards
    for item in email_items:
        assert item["plot_number"] is None
        assert item["call_date"] is None
