"""
WhatsApp Message Repository
"""

from typing import Optional, List, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text, select, and_
from datetime import datetime, timedelta
import structlog

from app.repositories.base import NotificationBaseRepository
from app.models.whatsapp_messages import WhatsAppMessage, WhatsAppMessageStatus, WhatsAppTemplate
from shared.database.exceptions import DatabaseError

logger = structlog.get_logger()


class WhatsAppMessageRepository(NotificationBaseRepository):
    """Repository for WhatsApp message operations"""

    def __init__(self, session: AsyncSession):
        super().__init__(WhatsAppMessage, session, cache_ttl=60)  # 1 minute cache

    async def create_message(self, message_data: Dict[str, Any]) -> WhatsAppMessage:
        """Create a new WhatsApp message record"""
        try:
            # Validate required fields
            validation = self._validate_notification_data(
                message_data,
                ["tenant_id", "recipient_phone", "message_type"]
            )

            if not validation["is_valid"]:
                raise DatabaseError(f"Validation failed: {', '.join(validation['errors'])}")

            message = await self.create(message_data)
            logger.info(
                "WhatsApp message created",
                message_id=str(message.id),
                recipient=message.recipient_phone,
                message_type=message.message_type.value
            )
            return message

        except Exception as e:
            logger.error("Failed to create WhatsApp message", error=str(e))
            raise DatabaseError(f"Failed to create message: {str(e)}")

    async def update_message_status(
        self,
        message_id: str,
        status: WhatsAppMessageStatus,
        whatsapp_message_id: Optional[str] = None,
        error_message: Optional[str] = None,
        provider_response: Optional[Dict] = None
    ) -> Optional[WhatsAppMessage]:
        """Update message status and related fields"""
        try:
            update_data = {
                "status": status,
                "updated_at": datetime.utcnow()
            }

            # Update timestamps based on status
            if status == WhatsAppMessageStatus.SENT:
                update_data["sent_at"] = datetime.utcnow()
            elif status == WhatsAppMessageStatus.DELIVERED:
                update_data["delivered_at"] = datetime.utcnow()
            elif status == WhatsAppMessageStatus.READ:
                update_data["read_at"] = datetime.utcnow()
            elif status == WhatsAppMessageStatus.FAILED:
                update_data["failed_at"] = datetime.utcnow()

            if whatsapp_message_id:
                update_data["whatsapp_message_id"] = whatsapp_message_id

            if error_message:
                update_data["error_message"] = error_message

            if provider_response:
                update_data["provider_response"] = provider_response

            message = await self.update(message_id, update_data)

            logger.info(
                "WhatsApp message status updated",
                message_id=message_id,
                status=status.value,
                whatsapp_message_id=whatsapp_message_id
            )

            return message

        except Exception as e:
            logger.error(
                "Failed to update message status",
                message_id=message_id,
                error=str(e)
            )
            return None

    async def get_by_whatsapp_id(self, whatsapp_message_id: str) -> Optional[WhatsAppMessage]:
        """Get message by WhatsApp's message ID"""
        try:
            messages = await self.get_multi(
                filters={"whatsapp_message_id": whatsapp_message_id},
                limit=1
            )
            return messages[0] if messages else None

        except Exception as e:
            logger.error(
                "Failed to get message by WhatsApp ID",
                whatsapp_message_id=whatsapp_message_id,
                error=str(e)
            )
            return None

    async def get_by_notification_id(self, notification_id: str) -> Optional[WhatsAppMessage]:
        """Get message by notification ID"""
        try:
            messages = await self.get_multi(
                filters={"notification_id": notification_id},
                limit=1
            )
            return messages[0] if messages else None

        except Exception as e:
            logger.error(
                "Failed to get message by notification ID",
                notification_id=notification_id,
                error=str(e)
            )
            return None

    async def get_messages_by_phone(
        self,
        tenant_id: str,
        phone: str,
        skip: int = 0,
        limit: int = 50
    ) -> List[WhatsAppMessage]:
        """Get all messages for a specific phone number"""
        try:
            return await self.get_multi(
                filters={"tenant_id": tenant_id, "recipient_phone": phone},
                skip=skip,
                limit=limit,
                order_by="created_at",
                order_desc=True
            )

        except Exception as e:
            logger.error(
                "Failed to get messages by phone",
                phone=phone,
                error=str(e)
            )
            return []

    async def get_pending_messages(
        self,
        tenant_id: str,
        limit: int = 100
    ) -> List[WhatsAppMessage]:
        """Get pending messages for retry processing"""
        try:
            return await self.get_multi(
                filters={
                    "tenant_id": tenant_id,
                    "status": WhatsAppMessageStatus.PENDING
                },
                limit=limit,
                order_by="created_at",
                order_desc=False  # Oldest first
            )

        except Exception as e:
            logger.error("Failed to get pending messages", error=str(e))
            return []

    async def get_conversation_messages(
        self,
        conversation_id: str,
        skip: int = 0,
        limit: int = 50
    ) -> List[WhatsAppMessage]:
        """Get all messages in a conversation"""
        try:
            return await self.get_multi(
                filters={"conversation_id": conversation_id},
                skip=skip,
                limit=limit,
                order_by="created_at",
                order_desc=False  # Chronological order
            )

        except Exception as e:
            logger.error(
                "Failed to get conversation messages",
                conversation_id=conversation_id,
                error=str(e)
            )
            return []

    async def get_delivery_stats(
        self,
        tenant_id: str,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None
    ) -> Dict[str, Any]:
        """Get delivery statistics for WhatsApp messages"""
        try:
            # Default to last 30 days
            if not start_date:
                start_date = datetime.utcnow() - timedelta(days=30)
            if not end_date:
                end_date = datetime.utcnow()

            query = text("""
                SELECT
                    COUNT(*) as total_messages,
                    COUNT(CASE WHEN status = 'SENT' THEN 1 END) as sent,
                    COUNT(CASE WHEN status = 'DELIVERED' THEN 1 END) as delivered,
                    COUNT(CASE WHEN status = 'READ' THEN 1 END) as read,
                    COUNT(CASE WHEN status = 'FAILED' THEN 1 END) as failed,
                    COUNT(CASE WHEN status = 'PENDING' THEN 1 END) as pending,
                    COUNT(DISTINCT recipient_phone) as unique_recipients,
                    COUNT(DISTINCT conversation_id) as total_conversations
                FROM whatsapp_messages
                WHERE tenant_id = :tenant_id
                AND created_at BETWEEN :start_date AND :end_date
            """)

            result = await self.session.execute(
                query,
                {
                    "tenant_id": tenant_id,
                    "start_date": start_date,
                    "end_date": end_date
                }
            )

            row = result.fetchone()

            if row:
                total = row.total_messages or 0
                delivered = row.delivered or 0

                return {
                    "total_messages": total,
                    "sent": row.sent or 0,
                    "delivered": delivered,
                    "read": row.read or 0,
                    "failed": row.failed or 0,
                    "pending": row.pending or 0,
                    "unique_recipients": row.unique_recipients or 0,
                    "total_conversations": row.total_conversations or 0,
                    "delivery_rate": round((delivered / total * 100), 2) if total > 0 else 0,
                    "period": {
                        "start": start_date.isoformat(),
                        "end": end_date.isoformat()
                    }
                }

            return {
                "total_messages": 0,
                "sent": 0,
                "delivered": 0,
                "read": 0,
                "failed": 0,
                "pending": 0,
                "unique_recipients": 0,
                "total_conversations": 0,
                "delivery_rate": 0,
                "period": {
                    "start": start_date.isoformat(),
                    "end": end_date.isoformat()
                }
            }

        except Exception as e:
            logger.error("Failed to get delivery stats", error=str(e))
            return {}


class WhatsAppTemplateRepository(NotificationBaseRepository):
    """Repository for WhatsApp template operations"""

    def __init__(self, session: AsyncSession):
        super().__init__(WhatsAppTemplate, session, cache_ttl=300)  # 5 minute cache

    async def get_by_template_name(
        self,
        template_name: str,
        language: str = "es"
    ) -> Optional[WhatsAppTemplate]:
        """Get template by name and language"""
        try:
            templates = await self.get_multi(
                filters={
                    "template_name": template_name,
                    "language": language,
                    "is_active": True
                },
                limit=1
            )
            return templates[0] if templates else None

        except Exception as e:
            logger.error(
                "Failed to get template by name",
                template_name=template_name,
                error=str(e)
            )
            return None

    async def get_by_template_key(self, template_key: str) -> Optional[WhatsAppTemplate]:
        """Get template by internal key"""
        try:
            templates = await self.get_multi(
                filters={"template_key": template_key},
                limit=1
            )
            return templates[0] if templates else None

        except Exception as e:
            logger.error(
                "Failed to get template by key",
                template_key=template_key,
                error=str(e)
            )
            return None

    async def get_active_templates(
        self,
        tenant_id: Optional[str] = None,
        category: Optional[str] = None
    ) -> List[WhatsAppTemplate]:
        """Get all active templates"""
        try:
            filters = {"is_active": True, "status": "APPROVED"}

            if tenant_id:
                filters["tenant_id"] = tenant_id

            if category:
                filters["category"] = category

            return await self.get_multi(
                filters=filters,
                limit=1000,
                order_by="created_at",
                order_desc=True
            )

        except Exception as e:
            logger.error("Failed to get active templates", error=str(e))
            return []

    async def increment_usage(self, template_id: str) -> None:
        """Increment template usage counter"""
        try:
            template = await self.get(template_id)
            if template:
                await self.update(
                    template_id,
                    {
                        "sent_count": (template.sent_count or 0) + 1,
                        "last_used_at": datetime.utcnow()
                    }
                )

        except Exception as e:
            logger.error(
                "Failed to increment template usage",
                template_id=template_id,
                error=str(e)
            )
