"""
Unit tests for WhatsApp event normalization to KonstructMessage.

Tests CHAN-03: Messages are normalized to the unified KonstructMessage format.

Covers:
- Text message normalizes correctly
- Image message normalizes with MediaAttachment
- Document message normalizes with MediaAttachment
- Correct field mapping: sender, channel, metadata
- ChannelType includes 'whatsapp'
- thread_id set to sender wa_id (WhatsApp has no threads)
- tenant_id is None after normalization
"""

from __future__ import annotations

from datetime import timezone

import pytest

from shared.models.message import ChannelType, MediaAttachment, MediaType


def make_text_webhook_payload(
    phone_number_id: str = "12345678901",
    wa_id: str = "5511987654321",
    message_id: str = "wamid.abc123",
    text: str = "Hello, I need help with my order",
    timestamp: str = "1711234567",
) -> dict:
    """Minimal valid Meta Cloud API v20.0 text message webhook payload."""
    return {
        "object": "whatsapp_business_account",
        "entry": [
            {
                "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
                "changes": [
                    {
                        "value": {
                            "messaging_product": "whatsapp",
                            "metadata": {
                                "display_phone_number": "15550000000",
                                "phone_number_id": phone_number_id,
                            },
                            "contacts": [
                                {
                                    "profile": {"name": "John Customer"},
                                    "wa_id": wa_id,
                                }
                            ],
                            "messages": [
                                {
                                    "from": wa_id,
                                    "id": message_id,
                                    "timestamp": timestamp,
                                    "text": {"body": text},
                                    "type": "text",
                                }
                            ],
                        },
                        "field": "messages",
                    }
                ],
            }
        ],
    }


def make_image_webhook_payload(
    phone_number_id: str = "12345678901",
    wa_id: str = "5511987654321",
    message_id: str = "wamid.img456",
    media_id: str = "media_id_xyz789",
    mime_type: str = "image/jpeg",
) -> dict:
    """Minimal valid Meta Cloud API v20.0 image message webhook payload."""
    return {
        "object": "whatsapp_business_account",
        "entry": [
            {
                "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
                "changes": [
                    {
                        "value": {
                            "messaging_product": "whatsapp",
                            "metadata": {
                                "display_phone_number": "15550000000",
                                "phone_number_id": phone_number_id,
                            },
                            "contacts": [
                                {
                                    "profile": {"name": "Jane Customer"},
                                    "wa_id": wa_id,
                                }
                            ],
                            "messages": [
                                {
                                    "from": wa_id,
                                    "id": message_id,
                                    "timestamp": "1711234567",
                                    "image": {
                                        "id": media_id,
                                        "mime_type": mime_type,
                                        "sha256": "abc123hash",
                                    },
                                    "type": "image",
                                }
                            ],
                        },
                        "field": "messages",
                    }
                ],
            }
        ],
    }


def make_document_webhook_payload(
    phone_number_id: str = "12345678901",
    wa_id: str = "5511987654321",
    message_id: str = "wamid.doc789",
    media_id: str = "media_id_doc001",
    filename: str = "invoice.pdf",
) -> dict:
    """Minimal valid Meta Cloud API v20.0 document message webhook payload."""
    return {
        "object": "whatsapp_business_account",
        "entry": [
            {
                "id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
                "changes": [
                    {
                        "value": {
                            "messaging_product": "whatsapp",
                            "metadata": {
                                "display_phone_number": "15550000000",
                                "phone_number_id": phone_number_id,
                            },
                            "contacts": [
                                {
                                    "profile": {"name": "Bob Customer"},
                                    "wa_id": wa_id,
                                }
                            ],
                            "messages": [
                                {
                                    "from": wa_id,
                                    "id": message_id,
                                    "timestamp": "1711234567",
                                    "document": {
                                        "id": media_id,
                                        "mime_type": "application/pdf",
                                        "filename": filename,
                                    },
                                    "type": "document",
                                }
                            ],
                        },
                        "field": "messages",
                    }
                ],
            }
        ],
    }


class TestChannelTypeWhatsApp:
    """Tests for ChannelType enum including WhatsApp."""

    def test_whatsapp_in_channel_type(self) -> None:
        """ChannelType enum must include 'whatsapp' value."""
        assert ChannelType.WHATSAPP == "whatsapp"
        assert "whatsapp" in [c.value for c in ChannelType]

    def test_whatsapp_channel_type_str(self) -> None:
        """ChannelType.WHATSAPP must equal string 'whatsapp'."""
        assert str(ChannelType.WHATSAPP) == "whatsapp"


class TestMediaAttachmentModel:
    """Tests for the MediaAttachment model."""

    def test_media_attachment_image_fields(self) -> None:
        """MediaAttachment must accept image type with required fields."""
        attachment = MediaAttachment(
            media_type=MediaType.IMAGE,
            mime_type="image/jpeg",
        )
        assert attachment.media_type == MediaType.IMAGE
        assert attachment.mime_type == "image/jpeg"
        assert attachment.url is None
        assert attachment.storage_key is None

    def test_media_attachment_document_with_filename(self) -> None:
        """MediaAttachment must accept document type with filename."""
        attachment = MediaAttachment(
            media_type=MediaType.DOCUMENT,
            mime_type="application/pdf",
            filename="report.pdf",
            size_bytes=102400,
        )
        assert attachment.media_type == MediaType.DOCUMENT
        assert attachment.filename == "report.pdf"
        assert attachment.size_bytes == 102400

    def test_media_attachment_all_fields_optional_except_type(self) -> None:
        """MediaAttachment requires only media_type; all other fields are optional."""
        attachment = MediaAttachment(media_type=MediaType.AUDIO)
        assert attachment.media_type == MediaType.AUDIO
        assert attachment.url is None
        assert attachment.storage_key is None
        assert attachment.mime_type is None
        assert attachment.filename is None
        assert attachment.size_bytes is None


class TestNormalizeWhatsAppText:
    """Tests for normalizing WhatsApp text messages."""

    def test_channel_type_is_whatsapp(self) -> None:
        """Normalized message must have channel=whatsapp."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert msg.channel == ChannelType.WHATSAPP

    def test_sender_user_id_is_wa_id(self) -> None:
        """sender.user_id must be the WhatsApp ID (wa_id) of the sender."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload(wa_id="5511987654321")
        msg = normalize_whatsapp_event(payload)
        assert msg.sender.user_id == "5511987654321"

    def test_content_text_extracted(self) -> None:
        """content.text must contain the message body text."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload(text="Can you help me track my order?")
        msg = normalize_whatsapp_event(payload)
        assert msg.content.text == "Can you help me track my order?"

    def test_channel_metadata_phone_number_id(self) -> None:
        """channel_metadata must contain phone_number_id."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload(phone_number_id="99988877766")
        msg = normalize_whatsapp_event(payload)
        assert msg.channel_metadata["phone_number_id"] == "99988877766"

    def test_channel_metadata_message_id(self) -> None:
        """channel_metadata must contain the WhatsApp message ID (wamid)."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload(message_id="wamid.unique123")
        msg = normalize_whatsapp_event(payload)
        assert msg.channel_metadata["message_id"] == "wamid.unique123"

    def test_thread_id_is_sender_wa_id(self) -> None:
        """thread_id must be the sender's wa_id (WhatsApp has no threads)."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload(wa_id="5511999998888")
        msg = normalize_whatsapp_event(payload)
        assert msg.thread_id == "5511999998888"

    def test_tenant_id_none_after_normalization(self) -> None:
        """tenant_id must be None immediately after normalization."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert msg.tenant_id is None

    def test_timestamp_is_utc(self) -> None:
        """timestamp must be a timezone-aware datetime in UTC."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload(timestamp="1711234567")
        msg = normalize_whatsapp_event(payload)
        assert msg.timestamp.tzinfo is not None
        assert msg.timestamp.tzinfo == timezone.utc

    def test_no_media_attachments_for_text_message(self) -> None:
        """Text message must not produce any media attachments."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_text_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert msg.content.media == []


class TestNormalizeWhatsAppImage:
    """Tests for normalizing WhatsApp image messages."""

    def test_image_message_has_media_attachment(self) -> None:
        """Image message must produce a MediaAttachment in content.media."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_image_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert len(msg.content.media) == 1

    def test_image_attachment_type_is_image(self) -> None:
        """MediaAttachment media_type must be IMAGE for image messages."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_image_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert msg.content.media[0].media_type == MediaType.IMAGE

    def test_image_attachment_mime_type(self) -> None:
        """MediaAttachment mime_type must be preserved from webhook payload."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_image_webhook_payload(mime_type="image/png")
        msg = normalize_whatsapp_event(payload)
        assert msg.content.media[0].mime_type == "image/png"

    def test_image_attachment_url_contains_media_id(self) -> None:
        """MediaAttachment url must contain the media_id as a placeholder for later download."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_image_webhook_payload(media_id="media_id_xyz789")
        msg = normalize_whatsapp_event(payload)
        assert msg.content.media[0].url is not None
        assert "media_id_xyz789" in msg.content.media[0].url

    def test_image_message_text_is_empty_string(self) -> None:
        """Image message with no caption must have empty string as text content."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_image_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert msg.content.text == ""


class TestNormalizeWhatsAppDocument:
    """Tests for normalizing WhatsApp document messages."""

    def test_document_message_has_media_attachment(self) -> None:
        """Document message must produce a MediaAttachment in content.media."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_document_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert len(msg.content.media) == 1

    def test_document_attachment_type_is_document(self) -> None:
        """MediaAttachment media_type must be DOCUMENT for document messages."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_document_webhook_payload()
        msg = normalize_whatsapp_event(payload)
        assert msg.content.media[0].media_type == MediaType.DOCUMENT

    def test_document_attachment_filename(self) -> None:
        """MediaAttachment filename must be preserved from webhook payload."""
        from gateway.normalize import normalize_whatsapp_event

        payload = make_document_webhook_payload(filename="contract.pdf")
        msg = normalize_whatsapp_event(payload)
        assert msg.content.media[0].filename == "contract.pdf"
