# app/modules/messaging/tests/integration/test_email_logs_api.py
"""
Integration tests for admin email logs (audit) API endpoints.

Tests the API routes at:
    GET  /api/v1/admin/email-logs
    GET  /api/v1/admin/email-logs/stats
    GET  /api/v1/admin/email-logs/{log_id}

Authentication: Uses super_admin_headers fixture (real JWT login).
"""

import uuid
from datetime import datetime

import pytest

from app.modules.messaging.models import EmailLog, EmailStatus

BASE = "/api/v1/admin/email-logs"


# =============================================================================
# FIXTURES
# =============================================================================


@pytest.fixture
def audit_logs(db):
    """Create email logs for integration testing."""
    logs = []

    # Sent logs
    for i in range(3):
        uid = uuid.uuid4().hex[:8]
        logs.append(EmailLog(
            template_code="signup_welcome",
            recipient_email=f"sent_{uid}@example.com",
            recipient_name=f"Sent User {i}",
            subject=f"Welcome {uid}",
            body_html=f"<p>Welcome {uid}</p>",
            body_text=f"Welcome {uid}",
            from_email="noreply@orion.lu",
            from_name="Orion",
            status=EmailStatus.SENT.value,
            provider="debug",
            sent_at=datetime.utcnow(),
        ))

    # Failed logs
    for i in range(2):
        uid = uuid.uuid4().hex[:8]
        logs.append(EmailLog(
            template_code="order_confirmation",
            recipient_email=f"failed_{uid}@example.com",
            recipient_name=f"Failed User {i}",
            subject=f"Order {uid}",
            body_html=f"<p>Order {uid}</p>",
            from_email="noreply@orion.lu",
            status=EmailStatus.FAILED.value,
            provider="smtp",
            error_message="Connection refused",
        ))

    # Pending log
    uid = uuid.uuid4().hex[:8]
    logs.append(EmailLog(
        template_code="team_invitation",
        recipient_email=f"pending_{uid}@example.com",
        subject=f"Invitation {uid}",
        from_email="noreply@orion.lu",
        status=EmailStatus.PENDING.value,
    ))

    db.add_all(logs)
    db.commit()
    for log in logs:
        db.refresh(log)
    return logs


# =============================================================================
# LIST EMAIL LOGS
# =============================================================================


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.email
class TestListEmailLogs:
    """Tests for GET /api/v1/admin/email-logs."""

    def test_list_logs_success(self, client, super_admin_headers, audit_logs):
        """Admin can list email logs."""
        response = client.get(BASE, headers=super_admin_headers)

        assert response.status_code == 200
        data = response.json()
        assert "items" in data
        assert "total" in data
        assert "page" in data
        assert "per_page" in data
        assert "total_pages" in data
        assert data["total"] == 6

    def test_list_logs_pagination(self, client, super_admin_headers, audit_logs):
        """Pagination parameters work correctly."""
        response = client.get(
            f"{BASE}?page=1&per_page=2",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert len(data["items"]) == 2
        assert data["total"] == 6
        assert data["page"] == 1
        assert data["per_page"] == 2
        assert data["total_pages"] == 3

    def test_list_logs_page_two(self, client, super_admin_headers, audit_logs):
        """Second page returns remaining items."""
        response = client.get(
            f"{BASE}?page=2&per_page=4",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert len(data["items"]) == 2
        assert data["page"] == 2

    def test_filter_by_status(self, client, super_admin_headers, audit_logs):
        """Filter by status returns matching logs."""
        response = client.get(
            f"{BASE}?status=sent",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 3
        assert all(item["status"] == "sent" for item in data["items"])

    def test_filter_by_template_code(self, client, super_admin_headers, audit_logs):
        """Filter by template_code returns matching logs."""
        response = client.get(
            f"{BASE}?template_code=order_confirmation",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 2
        assert all(
            item["template_code"] == "order_confirmation"
            for item in data["items"]
        )

    def test_filter_by_search(self, client, super_admin_headers, audit_logs):
        """Search filter matches recipient email."""
        email = audit_logs[0].recipient_email
        response = client.get(
            f"{BASE}?search={email}",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] >= 1
        assert any(email in item["recipient_email"] for item in data["items"])

    def test_combined_filters(self, client, super_admin_headers, audit_logs):
        """Multiple filters can be combined."""
        response = client.get(
            f"{BASE}?status=failed&template_code=order_confirmation",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 2

    def test_empty_result(self, client, super_admin_headers, audit_logs):
        """Non-matching filter returns empty list."""
        response = client.get(
            f"{BASE}?search=nonexistent_xyz@nowhere.test",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 0
        assert data["items"] == []

    def test_requires_auth(self, client, audit_logs):
        """Unauthenticated request is rejected."""
        response = client.get(BASE)
        assert response.status_code == 401

    def test_item_structure(self, client, super_admin_headers, audit_logs):
        """Response items have expected fields."""
        response = client.get(
            f"{BASE}?per_page=1",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        item = response.json()["items"][0]
        assert "id" in item
        assert "recipient_email" in item
        assert "subject" in item
        assert "status" in item
        assert "template_code" in item
        assert "created_at" in item
        # List items should NOT include body
        assert "body_html" not in item
        assert "body_text" not in item


# =============================================================================
# EMAIL LOG STATS
# =============================================================================


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.email
class TestEmailLogStats:
    """Tests for GET /api/v1/admin/email-logs/stats."""

    def test_stats_success(self, client, super_admin_headers, audit_logs):
        """Admin can retrieve email log stats."""
        response = client.get(
            f"{BASE}/stats",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert "by_status" in data
        assert "by_template" in data
        assert "total" in data

    def test_stats_status_counts(self, client, super_admin_headers, audit_logs):
        """Stats include correct counts by status."""
        response = client.get(
            f"{BASE}/stats",
            headers=super_admin_headers,
        )

        data = response.json()
        assert data["by_status"]["sent"] == 3
        assert data["by_status"]["failed"] == 2
        assert data["by_status"]["pending"] == 1
        assert data["total"] == 6

    def test_stats_template_counts(self, client, super_admin_headers, audit_logs):
        """Stats include correct counts by template."""
        response = client.get(
            f"{BASE}/stats",
            headers=super_admin_headers,
        )

        data = response.json()
        assert data["by_template"]["signup_welcome"] == 3
        assert data["by_template"]["order_confirmation"] == 2
        assert data["by_template"]["team_invitation"] == 1

    def test_stats_requires_auth(self, client, audit_logs):
        """Unauthenticated request is rejected."""
        response = client.get(f"{BASE}/stats")
        assert response.status_code == 401

    def test_stats_empty_database(self, client, super_admin_headers):
        """Stats return zeros when no logs exist."""
        response = client.get(
            f"{BASE}/stats",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["total"] == 0


# =============================================================================
# EMAIL LOG DETAIL
# =============================================================================


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.email
class TestEmailLogDetail:
    """Tests for GET /api/v1/admin/email-logs/{log_id}."""

    def test_detail_success(self, client, super_admin_headers, audit_logs):
        """Admin can retrieve full log detail."""
        log_id = audit_logs[0].id
        response = client.get(
            f"{BASE}/{log_id}",
            headers=super_admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["id"] == log_id
        assert data["recipient_email"] == audit_logs[0].recipient_email
        assert data["body_html"] is not None
        assert data["from_email"] == "noreply@orion.lu"

    def test_detail_includes_body(self, client, super_admin_headers, audit_logs):
        """Detail response includes body_html and body_text."""
        log_id = audit_logs[0].id
        response = client.get(
            f"{BASE}/{log_id}",
            headers=super_admin_headers,
        )

        data = response.json()
        assert "body_html" in data
        assert "body_text" in data
        assert data["body_html"] is not None

    def test_detail_includes_timestamps(self, client, super_admin_headers, audit_logs):
        """Detail response includes all timestamp fields."""
        log_id = audit_logs[0].id
        response = client.get(
            f"{BASE}/{log_id}",
            headers=super_admin_headers,
        )

        data = response.json()
        assert "created_at" in data
        assert "sent_at" in data
        assert "delivered_at" in data
        assert "opened_at" in data
        assert "clicked_at" in data

    def test_detail_failed_log_has_error(self, client, super_admin_headers, audit_logs):
        """Failed log detail includes error message."""
        failed_log = next(log for log in audit_logs if log.status == EmailStatus.FAILED.value)
        response = client.get(
            f"{BASE}/{failed_log.id}",
            headers=super_admin_headers,
        )

        data = response.json()
        assert data["status"] == "failed"
        assert data["error_message"] == "Connection refused"

    def test_detail_not_found(self, client, super_admin_headers):
        """Non-existent log returns 404."""
        response = client.get(
            f"{BASE}/999999",
            headers=super_admin_headers,
        )

        assert response.status_code == 404

    def test_detail_requires_auth(self, client, audit_logs):
        """Unauthenticated request is rejected."""
        log_id = audit_logs[0].id
        response = client.get(f"{BASE}/{log_id}")
        assert response.status_code == 401
