"""WhatsApp Message Template schema definitions using Pydantic models.

This module provides type-safe models for WhatsApp Message Templates,
covering both template creation (registration) and send message payloads.
"""

from __future__ import annotations

from typing import Any, Dict, List, Literal, Optional, Union

from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator


class TemplateBaseModel(BaseModel):
    """Base model with WhatsApp Template-specific configuration."""

    model_config = ConfigDict(
        extra="ignore",
        populate_by_name=True,
    )

    def model_dump(self, **kwargs: Any) -> dict[str, Any]:
        """Override to exclude None values by default."""
        kwargs.setdefault("exclude_none", True)
        kwargs.setdefault("by_alias", True)
        return super().model_dump(**kwargs)

    def model_dump_json(self, **kwargs: Any) -> str:
        """Override to exclude None values by default."""
        kwargs.setdefault("exclude_none", True)
        kwargs.setdefault("by_alias", True)
        return super().model_dump_json(**kwargs)


# ========== TEMPLATE CREATION MODELS ==========

# ---------- Header Component ----------
class HeaderComponent(TemplateBaseModel):
    """Header component for template creation."""

    type: Literal["HEADER"]
    format: Literal["TEXT", "IMAGE", "VIDEO", "DOCUMENT", "LOCATION"]
    text: Optional[str] = None  # Only for TEXT format


# ---------- Body Component ----------
class BodyComponent(TemplateBaseModel):
    """Body component for template creation."""

    type: Literal["BODY"]
    text: str  # Text with {{1}}, {{2}} style placeholders


# ---------- Footer Component ----------
class FooterComponent(TemplateBaseModel):
    """Footer component for template creation."""

    type: Literal["FOOTER"]
    text: str


# ---------- Button Types ----------
class QuickReplyButton(TemplateBaseModel):
    """Quick reply button."""

    type: Literal["QUICK_REPLY"]
    text: str


class UrlButton(TemplateBaseModel):
    """URL button."""

    type: Literal["URL"]
    text: str
    url: str


class PhoneNumberButton(TemplateBaseModel):
    """Phone number / Call button."""

    type: Literal["PHONE_NUMBER"]
    text: str
    phone_number: str


TemplateButton = Union[QuickReplyButton, UrlButton, PhoneNumberButton]


# ---------- Buttons Component ----------
class ButtonsComponent(TemplateBaseModel):
    """Buttons component for template creation.

    Rules:
    - Max 3 Quick Reply buttons
    - Max 2 URL buttons
    - Max 1 Phone Number button
    """

    type: Literal["BUTTONS"]
    buttons: List[TemplateButton]

    @model_validator(mode="after")
    def validate_button_limits(self) -> "ButtonsComponent":
        """Enforce WhatsApp button count limits."""
        quick_reply_count = sum(
            1 for b in self.buttons if isinstance(b, QuickReplyButton)
        )
        url_count = sum(1 for b in self.buttons if isinstance(b, UrlButton))
        phone_count = sum(
            1 for b in self.buttons if isinstance(b, PhoneNumberButton)
        )

        if quick_reply_count > 3:
            raise ValueError(
                f"Max 3 Quick Reply buttons allowed, got {quick_reply_count}"
            )
        if url_count > 2:
            raise ValueError(f"Max 2 URL buttons allowed, got {url_count}")
        if phone_count > 1:
            raise ValueError(f"Max 1 Phone Number button allowed, got {phone_count}")

        return self


CreationComponent = Union[
    HeaderComponent, BodyComponent, FooterComponent, ButtonsComponent
]


# ---------- Template Creation (register with Meta) ----------
class TemplateCreation(TemplateBaseModel):
    """Template creation payload for registering with Meta.

    This is sent to the WhatsApp Business API to create a new template
    that must be approved before it can be used.
    """

    name: str
    language: str = "en_US"
    category: Literal["MARKETING", "UTILITY", "AUTHENTICATION"]
    components: List[CreationComponent]

    @model_validator(mode="after")
    def validate_components(self) -> "TemplateCreation":
        """Ensure at least a BODY component exists."""
        body_count = sum(
            1 for c in self.components if isinstance(c, BodyComponent)
        )
        if body_count == 0:
            raise ValueError("Template must have at least one BODY component")
        if body_count > 1:
            raise ValueError("Template must have exactly one BODY component")
        return self


# ========== SEND MESSAGE MODELS ==========

# ---------- Send Parameters ----------
class TextParameter(TemplateBaseModel):
    """Text parameter for send payload."""

    type: Literal["text"]
    text: str


class ImageMedia(TemplateBaseModel):
    """Image media object."""

    link: str


class ImageParameter(TemplateBaseModel):
    """Image parameter for send payload."""

    type: Literal["image"]
    image: ImageMedia


class VideoMedia(TemplateBaseModel):
    """Video media object."""

    link: str


class VideoParameter(TemplateBaseModel):
    """Video parameter for send payload."""

    type: Literal["video"]
    video: VideoMedia


class DocumentMedia(TemplateBaseModel):
    """Document media object."""

    link: str
    filename: Optional[str] = None


class DocumentParameter(TemplateBaseModel):
    """Document parameter for send payload."""

    type: Literal["document"]
    document: DocumentMedia


SendParameter = Union[TextParameter, ImageParameter, VideoParameter, DocumentParameter]


# ---------- Send Component ----------
class SendComponent(TemplateBaseModel):
    """Component in the send message payload."""

    type: Literal["header", "body", "button"]
    parameters: List[SendParameter] = Field(default_factory=list)
    sub_type: Optional[Literal["quick_reply", "url"]] = None
    index: Optional[int] = None


# ---------- Language ----------
class TemplateLanguage(TemplateBaseModel):
    """Language specification for send payload."""

    code: str


# ---------- Template Send Info ----------
class TemplateSendInfo(TemplateBaseModel):
    """Template reference in the send payload."""

    name: str
    language: TemplateLanguage
    components: List[SendComponent] = Field(default_factory=list)


# ---------- Template Send (send to user) ----------
class TemplateSend(TemplateBaseModel):
    """Send message payload for sending a template to a user.

    This is sent to the WhatsApp Cloud API /messages endpoint.
    """

    messaging_product: Literal["whatsapp"] = "whatsapp"
    to: str = "<PHONE_NUMBER>"
    type: Literal["template"] = "template"
    template: TemplateSendInfo


# ========== COMBINED RESULT ==========

class TemplateResult(TemplateBaseModel):
    """Combined result containing both creation and send payloads.

    This is the main output type from generate_template().
    """

    creation: TemplateCreation
    send: TemplateSend


# ========== VALIDATION HELPERS ==========

def validate_template_creation(data: Any) -> dict[str, Any]:
    """Validate arbitrary data as a TemplateCreation.

    Args:
        data: Dictionary or object to validate.

    Returns:
        {"success": True, "data": TemplateCreation} or
        {"success": False, "error": ValidationError}
    """
    try:
        result = TemplateCreation.model_validate(data)
        return {"success": True, "data": result}
    except ValidationError as exc:
        return {"success": False, "error": exc}


def validate_template_result(data: Any) -> dict[str, Any]:
    """Validate arbitrary data as a TemplateResult.

    Args:
        data: Dictionary or object to validate.

    Returns:
        {"success": True, "data": TemplateResult} or
        {"success": False, "error": ValidationError}
    """
    try:
        result = TemplateResult.model_validate(data)
        return {"success": True, "data": result}
    except ValidationError as exc:
        return {"success": False, "error": exc}
