"""
Microsoft Teams Webhook library.

Provides a simple interface for sending adaptive card messages to Teams via webhooks.
"""

import json
import requests
from typing import Any, Optional
from enum import Enum


class MessageStatus(str, Enum):
    """Message status types."""
    SUCCESS = "Success"
    ERROR = "Error"
    WARNING = "Warning"
    INFO = "Info"


def _format_object_to_markdown(obj: Any) -> str:
    """Convert an object to a markdown formatted string.
    
    Args:
        obj: Any object (dict, list, string, or other)
        
    Returns:
        A markdown formatted string representation of the object
    """
    # Handle string input - try to parse as JSON
    if isinstance(obj, str):
        try:
            obj = json.loads(obj)
        except json.JSONDecodeError:
            return obj
    
    # If not a dict after parsing, just convert to string
    if not isinstance(obj, dict):
        return f"Object is not JSON parsable\n{str(obj)}"
    
    entries = []
    for key, value in obj.items():
        if isinstance(value, list):
            if value and all(isinstance(item, dict) for item in value):
                # List of objects
                items_str = ", \n * ".join(json.dumps(item) for item in value)
                entries.append(f"**{key}** : {items_str} \n")
            else:
                # Simple list
                items_str = ", \n * ".join(str(item) for item in value)
                entries.append(f"**{key}** : {items_str} \n")
        elif isinstance(value, dict):
            entries.append(f"**{key}** : {json.dumps(value)} \n")
        else:
            entries.append(f"**{key}** : {value}")
    
    return "\n * " + ", \n * ".join(entries) + " \n"


def _get_status_emoji(status: str) -> str:
    """Get an emoji representation for the status.
    
    Args:
        status: The status string
        
    Returns:
        An emoji character representing the status
    """
    status_map = {
        "error": "❌",
        "warning": "⚠️",
        "success": "✅",
        "info": "ℹ️",
    }
    return status_map.get(status.lower(), "✅")


def _create_default_payload(
    title: str,
    data_source: str,
    message: Any,
    status: str,
    environment: Optional[str] = None,
    responsible_party: Optional[str] = None,
    custom_fields: Optional[dict[str, Any]] = None,
) -> dict[str, Any]:
    """Create the default adaptive card payload.
    
    Args:
        title: The title of the message
        data_source: The source of the data
        message: The message content (can be any type)
        status: The status of the message
        environment: The environment name (development, production, etc.)
        responsible_party: The responsible party/team member
        custom_fields: Additional custom fields to include
        
    Returns:
        The adaptive card payload as a dictionary
    """
    # Handle response-like objects
    if isinstance(message, dict) and "response" in message:
        response = message["response"]
        if isinstance(response, dict):
            message = json.dumps({
                "status": response.get("status"),
                "statusText": response.get("statusText"),
                "data": response.get("data"),
            })
    
    formatted_message = _format_object_to_markdown(message)
    
    # Build base body elements
    body = [
        {
            "type": "TextBlock",
            "text": f"**{title}**",
            "style": "heading",
        },
        {
            "type": "TextBlock",
            "text": f"**Server**: {environment or 'Unknown'}",
            "style": "heading",
        },
        {
            "type": "TextBlock",
            "text": f"**Source**: {data_source}",
        },
        {
            "type": "TextBlock",
            "text": f"**Status**: {status} {_get_status_emoji(status)}",
        },
        {
            "type": "TextBlock",
            "text": f"**Message**: \n{formatted_message}",
            "wrap": True,
        },
    ]
    
    # Add responsible party if provided
    if responsible_party:
        body.append({
            "type": "TextBlock",
            "text": f"**Responsible Party**: {responsible_party}",
            "wrap": True,
        })
    
    # Add custom fields if provided
    if custom_fields:
        for key, value in custom_fields.items():
            body.append({
                "type": "TextBlock",
                "text": f"**{key}**: {value}",
                "wrap": True,
            })
    
    return {
        "type": "message",
        "attachments": [
            {
                "contentType": "application/vnd.microsoft.card.adaptive",
                "contentUrl": None,
                "content": {
                    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                    "type": "AdaptiveCard",
                    "version": "1.2",
                    "body": body,
                    "msteams": {
                        "entities": []
                    },
                },
            },
        ],
    }


class TeamsWebhook:
    """Microsoft Teams Webhook client.
    
    Provides a simple interface for sending messages to Teams channels
    via incoming webhooks with adaptive card formatting.
    
    Examples:
        >>> # Single webhook URL for all messages
        >>> webhook = TeamsWebhook("https://teams.webhook.office.com/...")
        >>> webhook.send("Test", {"key": "value"}, "My App", "Success")
        
        >>> # Separate webhooks for success and error messages
        >>> webhook = TeamsWebhook(
        ...     success_webhook_url="https://teams.webhook.office.com/success...",
        ...     error_webhook_url="https://teams.webhook.office.com/error..."
        ... )
        >>> webhook.send("Error Alert", "Something failed", "My App", "Error")
    """
    
    def __init__(
        self,
        webhook_url: Optional[str] = None,
        success_webhook_url: Optional[str] = None,
        error_webhook_url: Optional[str] = None,
        environment: Optional[str] = None,
        responsible_party: Optional[str] = None,
    ):
        """Initialize the Teams webhook client.
        
        Args:
            webhook_url: A single webhook URL for all message types.
                         If provided, this will be used for all messages.
            success_webhook_url: Webhook URL for success/info messages.
                                 Required if webhook_url is not provided.
            error_webhook_url: Webhook URL for error/warning messages.
                               Required if webhook_url is not provided.
            environment: The environment name (e.g., "development", "production")
            responsible_party: The default responsible party/team member
            
        Raises:
            ValueError: If no webhook URLs are provided
        """
        if webhook_url:
            self._webhook_url = webhook_url
            self._success_webhook_url = webhook_url
            self._error_webhook_url = webhook_url
        elif success_webhook_url and error_webhook_url:
            self._webhook_url = None
            self._success_webhook_url = success_webhook_url
            self._error_webhook_url = error_webhook_url
        else:
            raise ValueError(
                "Either webhook_url must be provided, "
                "or both success_webhook_url and error_webhook_url must be provided"
            )
        
        self._environment = environment
        self._responsible_party = responsible_party
    
    def _get_webhook_url(self, status: str) -> Optional[str]:
        """Get the appropriate webhook URL based on status.
        
        Args:
            status: The message status
            
        Returns:
            The webhook URL to use
        """
        if self._webhook_url:
            return self._webhook_url
        
        status_lower = status.lower()
        if status_lower in ("error", "warning"):
            return self._error_webhook_url
        return self._success_webhook_url
    
    def send(
        self,
        title: str,
        message: Any,
        data_source: str,
        status: str,
        payload: Optional[dict[str, Any]] = None,
        responsible_party: Optional[str] = None,
        custom_fields: Optional[dict[str, Any]] = None,
    ) -> bool:
        """Send a message to Teams.
        
        Args:
            title: The title of the message
            message: The message content (can be string, dict, list, or any object)
            data_source: The source of the data (e.g., application name, service name)
            status: The status of the message ("Success", "Error", "Warning", "Info")
            payload: Optional custom adaptive card payload. If not provided,
                     a default payload will be generated.
            responsible_party: Optional override for the responsible party.
                               If not provided, uses the default from constructor.
            custom_fields: Optional additional fields to include in the message
            
        Returns:
            True if the message was sent successfully, False otherwise
        """
        webhook_url = self._get_webhook_url(status)
        
        if not webhook_url:
            print("NO AVAILABLE WEBHOOK URL")
            print(f"{title}: {message}")
            return False
        
        # Use custom payload if provided, otherwise generate default
        if payload is not None:
            card_payload = payload
        else:
            card_payload = _create_default_payload(
                title=title,
                data_source=data_source,
                message=message,
                status=status,
                environment=self._environment,
                responsible_party=responsible_party or self._responsible_party,
                custom_fields=custom_fields,
            )
        
        try:
            response = requests.post(
                webhook_url,
                json=card_payload,
                headers={"Content-Type": "application/json"},
                timeout=30,
            )
            response.raise_for_status()
            print(f"Sent: {title} ({data_source})")
            print(f"Status Code: {response.status_code}")
            return True
        except requests.exceptions.RequestException as e:
            print(f"Error sending webhook: {e}")
            return False
    
    def send_success(
        self,
        title: str,
        message: Any,
        data_source: str,
        **kwargs: Any,
    ) -> bool:
        """Send a success message to Teams.
        
        Convenience method for sending success status messages.
        
        Args:
            title: The title of the message
            message: The message content
            data_source: The source of the data
            **kwargs: Additional arguments passed to send()
            
        Returns:
            True if the message was sent successfully, False otherwise
        """
        return self.send(title, message, data_source, MessageStatus.SUCCESS, **kwargs)
    
    def send_error(
        self,
        title: str,
        message: Any,
        data_source: str,
        **kwargs: Any,
    ) -> bool:
        """Send an error message to Teams.
        
        Convenience method for sending error status messages.
        
        Args:
            title: The title of the message
            message: The message content
            data_source: The source of the data
            **kwargs: Additional arguments passed to send()
            
        Returns:
            True if the message was sent successfully, False otherwise
        """
        return self.send(title, message, data_source, MessageStatus.ERROR, **kwargs)
    
    def send_warning(
        self,
        title: str,
        message: Any,
        data_source: str,
        **kwargs: Any,
    ) -> bool:
        """Send a warning message to Teams.
        
        Convenience method for sending warning status messages.
        
        Args:
            title: The title of the message
            message: The message content
            data_source: The source of the data
            **kwargs: Additional arguments passed to send()
            
        Returns:
            True if the message was sent successfully, False otherwise
        """
        return self.send(title, message, data_source, MessageStatus.WARNING, **kwargs)
    
    def send_info(
        self,
        title: str,
        message: Any,
        data_source: str,
        **kwargs: Any,
    ) -> bool:
        """Send an info message to Teams.
        
        Convenience method for sending info status messages.
        
        Args:
            title: The title of the message
            message: The message content
            data_source: The source of the data
            **kwargs: Additional arguments passed to send()
            
        Returns:
            True if the message was sent successfully, False otherwise
        """
        return self.send(title, message, data_source, MessageStatus.INFO, **kwargs)
