"""
MIT License Copyright (c) 2025-present June

Permission is hereby granted, free of
charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice
(including the next paragraph) shall be included in all copies or substantial
portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

from dataclasses import dataclass
from datetime import datetime
from typing import Any, Dict, List, Optional


@dataclass
class ChannelEventError:
    """Represents an error from the messaging channel.

    Attributes:
        channel_code: The error code from the channel.
        channel_message: The error message from the channel.
    """

    channel_code: Optional[str] = None
    channel_message: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ChannelEventError":
        """Create a ChannelEventError from a dictionary.

        Args:
            data: Dictionary containing channel error data.

        Returns:
            ChannelEventError instance.
        """
        return cls(channel_code=data.get("channelCode"), channel_message=data.get("channelMessage"))


@dataclass
class MediaContent:
    """Represents media content (image, video, audio, document).

    Attributes:
        mime_type: The MIME type of the media.
        id: Unique identifier for the media.
        file_name: Optional file name of the media.
        caption: Optional caption for the media.
        animated: Whether the media is animated (e.g., sticker).
    """

    mime_type: str
    id: str
    file_name: Optional[str] = None
    caption: Optional[str] = None
    animated: Optional[bool] = None

    def _get_filename(self) -> str:
        """Generate a filename for the media based on its ID and MIME type."""
        extension = self.mime_type.split("/")[-1] if "/" in self.mime_type else "bin"
        return f"{self.id}.{extension}"

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "MediaContent":
        """Create MediaContent from a dictionary.

        Args:
            data: Dictionary containing media content data.

        Returns:
            MediaContent instance.
        """
        instance = cls(
            mime_type=data.get("mimeType"),
            id=data.get("id") or data.get("ID"),
            file_name=None,
            caption=data.get("caption"),
            animated=data.get("animated"),
        )
        if not instance.file_name:
            instance.file_name = instance._get_filename()
        return instance


@dataclass
class MessageContext:
    """Context information about a message (reply-to context).

    Attributes:
        from_id: ID of the user who sent the original message being replied to.
        id: ID of the original message being replied to.
    """

    from_id: Optional[str] = None
    id: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "MessageContext":
        """Create MessageContext from a dictionary.

        Args:
            data: Dictionary containing message context data.

        Returns:
            MessageContext instance.
        """
        return cls(from_id=data.get("from"), id=data.get("id") or data.get("ID"))


@dataclass
class ButtonContent:
    """Represents a button press in a quick reply.

    Attributes:
        text: The text displayed on the button.
        payload: The payload/value sent when button is pressed.
    """

    text: Optional[str] = None
    payload: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ButtonContent":
        """Create ButtonContent from a dictionary.

        Args:
            data: Dictionary containing button data.

        Returns:
            ButtonContent instance.
        """
        return cls(text=data.get("text"), payload=data.get("payload"))


@dataclass
class InteractiveButtonReplyContent:
    """Represents a button reply from an interactive message.

    Attributes:
        id: The ID of the button pressed.
        title: The title text of the button.
    """

    id: Optional[str] = None
    title: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "InteractiveButtonReplyContent":
        """Create InteractiveButtonReplyContent from a dictionary.

        Args:
            data: Dictionary containing button reply data.

        Returns:
            InteractiveButtonReplyContent instance.
        """
        return cls(id=data.get("id") or data.get("ID"), title=data.get("title"))


@dataclass
class InteractiveListReplyContent:
    """Represents a list item selection from an interactive message.

    Attributes:
        id: The ID of the selected list item.
        title: The title of the selected item.
        description: The description of the selected item.
    """

    id: Optional[str] = None
    title: Optional[str] = None
    description: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "InteractiveListReplyContent":
        """Create InteractiveListReplyContent from a dictionary.

        Args:
            data: Dictionary containing list reply data.

        Returns:
            InteractiveListReplyContent instance.
        """
        return cls(id=data.get("id") or data.get("ID"), title=data.get("title"), description=data.get("description"))


@dataclass
class InteractiveContent:
    """Represents interactive content from an interactive message.

    Attributes:
        type: The type of interactive message (e.g., 'button_reply', 'list_reply').
        button_reply: Button reply content if the message was a button press.
        list_reply: List reply content if the message was a list selection.
    """

    type: Optional[str] = None
    button_reply: Optional[InteractiveButtonReplyContent] = None
    list_reply: Optional[InteractiveListReplyContent] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "InteractiveContent":
        """Create InteractiveContent from a dictionary.

        Args:
            data: Dictionary containing interactive content data.

        Returns:
            InteractiveContent instance.
        """
        return cls(
            type=data.get("type"),
            button_reply=InteractiveButtonReplyContent.from_dict(data.get("buttonReply"))
            if data.get("buttonReply")
            else None,
            list_reply=InteractiveListReplyContent.from_dict(data.get("listReply")) if data.get("listReply") else None,
        )


@dataclass
class ReactionContent:
    """Represents a reaction (emoji) to a message.

    Attributes:
        message_id: The ID of the message being reacted to.
        emoji: The emoji used for the reaction.
    """

    message_id: str
    emoji: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ReactionContent":
        """Create ReactionContent from a dictionary.

        Args:
            data: Dictionary containing reaction data.

        Returns:
            ReactionContent instance.
        """
        return cls(message_id=data.get("messageId"), emoji=data.get("emoji"))


@dataclass
class LanguageDetection:
    """Represents language detection analysis results.

    Attributes:
        language: Detected language code (e.g., 'en', 'es').
        confidence_score: Confidence level of the detection (0-1).
        translation: Optional translation of the message.
    """

    language: Optional[str] = None
    confidence_score: Optional[float] = None
    translation: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "LanguageDetection":
        """Create LanguageDetection from a dictionary.

        Args:
            data: Dictionary containing language detection data.

        Returns:
            LanguageDetection instance.
        """
        return cls(
            language=data.get("language"),
            confidence_score=data.get("confidenceScore"),
            translation=data.get("translation"),
        )


@dataclass
class AdvancedMessageReceivedEvent:
    """Represents an incoming message event from Azure ACS.

    Attributes:
        channel_type: The messaging channel type (e.g., 'whatsapp').
        from_id: The user ID (phone number) sending the message.
        to: The recipient ID (phone number).
        received_timestamp: When the message was received.
        message_id: Unique identifier for the message.
        message_type: Type of message (text, media, interactive, etc.).
        content: Text content of the message.
        media: Media content if the message contains media.
        context: Reply context if this is a reply to another message.
        button: Button content if this is a quick reply button press.
        interactive: Interactive content if from interactive message.
        reaction: Reaction content if this is a reaction message.
    """

    channel_type: str
    from_id: str
    to: str
    received_timestamp: datetime
    message_id: str
    message_type: str
    content: Optional[str] = None
    media: Optional[MediaContent] = None
    context: Optional[MessageContext] = None
    button: Optional[ButtonContent] = None
    interactive: Optional[InteractiveContent] = None
    reaction: Optional[ReactionContent] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "AdvancedMessageReceivedEvent":
        """Create AdvancedMessageReceivedEvent from a dictionary.

        Args:
            data: Dictionary containing message event data from Azure ACS.

        Returns:
            AdvancedMessageReceivedEvent instance.
        """
        return cls(
            channel_type=data.get("channelType"),
            from_id=data.get("from"),
            to=data.get("to"),
            received_timestamp=datetime.fromisoformat(data.get("receivedTimestamp").replace("Z", "+00:00")),
            message_id=data.get("messageId"),
            message_type=data.get("messageType"),
            content=data.get("content"),
            media=MediaContent.from_dict(data.get("media")) if data.get("media") else None,
            context=MessageContext.from_dict(data.get("context")) if data.get("context") else None,
            button=ButtonContent.from_dict(data.get("button")) if data.get("button") else None,
            interactive=InteractiveContent.from_dict(data.get("interactive")) if data.get("interactive") else None,
            reaction=ReactionContent.from_dict(data.get("reaction")) if data.get("reaction") else None,
        )


@dataclass
class AdvancedMessageDeliveryStatusUpdatedEvent:
    """Represents a message delivery status update event from Azure ACS.

    Attributes:
        channel_type: The messaging channel type (e.g., 'whatsapp').
        from_id: The sender ID (phone number).
        to: The recipient ID (phone number).
        received_timestamp: When the status update was received.
        status: The delivery status (e.g., 'sent', 'delivered', 'read', 'failed').
        message_id: ID of the message being reported on.
        error: Error details if the delivery failed.
    """

    channel_type: str
    from_id: str
    to: str
    received_timestamp: datetime
    status: str
    message_id: Optional[str] = None
    error: Optional[ChannelEventError] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "AdvancedMessageDeliveryStatusUpdatedEvent":
        """Create AdvancedMessageDeliveryStatusUpdatedEvent from a dictionary.

        Args:
            data: Dictionary containing delivery status update data from Azure ACS.

        Returns:
            AdvancedMessageDeliveryStatusUpdatedEvent instance.
        """
        return cls(
            channel_type=data.get("channelType"),
            from_id=data.get("from"),
            to=data.get("to"),
            received_timestamp=datetime.fromisoformat(data.get("receivedTimestamp").replace("Z", "+00:00")),
            status=data.get("status"),
            message_id=data.get("messageId"),
            error=ChannelEventError.from_dict(data.get("error")) if data.get("error") else None,
        )


@dataclass
class AdvancedMessageAnalysisCompletedEvent:
    """Represents a message analysis completion event from Azure ACS.

    Attributes:
        channel_type: The messaging channel type (e.g., 'whatsapp').
        from_id: The sender ID (phone number).
        to: The recipient ID (phone number).
        received_timestamp: When the analysis was completed.
        original_message: The original message text.
        intent_analysis: Analysis of the user's intent.
        language_detection: Detected language and confidence information.
        extracted_key_phrases: List of key phrases extracted from the message.
    """

    channel_type: Optional[str]
    from_id: Optional[str]
    to: Optional[str]
    received_timestamp: Optional[datetime]
    original_message: Optional[str]
    intent_analysis: Optional[str]
    language_detection: Optional[LanguageDetection] = None
    extracted_key_phrases: Optional[List[str]] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "AdvancedMessageAnalysisCompletedEvent":
        """Create AdvancedMessageAnalysisCompletedEvent from a dictionary.

        Args:
            data: Dictionary containing message analysis data from Azure ACS.

        Returns:
            AdvancedMessageAnalysisCompletedEvent instance.
        """
        return cls(
            channel_type=data.get("channelType"),
            from_id=data.get("from"),
            to=data.get("to"),
            received_timestamp=datetime.fromisoformat(data.get("receivedTimestamp").replace("Z", "+00:00"))
            if data.get("receivedTimestamp")
            else None,
            original_message=data.get("originalMessage"),
            intent_analysis=data.get("intentAnalysis"),
            language_detection=LanguageDetection.from_dict(data.get("languageDetection"))
            if data.get("languageDetection")
            else None,
            extracted_key_phrases=data.get("extractedKeyPhrases"),
        )
