# ================================================================
# services/notification/app/services/whatsapp_service.py
# ================================================================
"""
WhatsApp service for sending notifications
Integrates with WhatsApp Business API via Twilio
"""

import structlog
import httpx
from typing import Optional, Dict, Any, List
import asyncio
from urllib.parse import quote

from app.core.config import settings
from shared.monitoring.metrics import MetricsCollector

logger = structlog.get_logger()
metrics = MetricsCollector("notification-service")

class WhatsAppService:
    """
    WhatsApp service for sending notifications via Twilio WhatsApp API
    Supports text messages and template messages
    """
    
    def __init__(self):
        self.api_key = settings.WHATSAPP_API_KEY
        self.base_url = settings.WHATSAPP_BASE_URL
        self.from_number = settings.WHATSAPP_FROM_NUMBER
        self.enabled = settings.ENABLE_WHATSAPP_NOTIFICATIONS
    
    def _parse_api_credentials(self):
        """Parse API key into username and password for Twilio basic auth"""
        if not self.api_key or ":" not in self.api_key:
            raise ValueError("WhatsApp API key must be in format 'username:password'")
        
        api_parts = self.api_key.split(":", 1)
        if len(api_parts) != 2:
            raise ValueError("Invalid WhatsApp API key format")
        
        return api_parts[0], api_parts[1]
    
    async def send_message(
        self,
        to_phone: str,
        message: str,
        template_name: Optional[str] = None,
        template_params: Optional[List[str]] = None
    ) -> bool:
        """
        Send WhatsApp message
        
        Args:
            to_phone: Recipient phone number (with country code)
            message: Message text
            template_name: WhatsApp template name (optional)
            template_params: Template parameters (optional)
        
        Returns:
            bool: True if message was sent successfully
        """
        try:
            if not self.enabled:
                logger.info("WhatsApp notifications disabled")
                return True  # Return success to avoid blocking workflow
            
            if not self.api_key:
                logger.error("WhatsApp API key not configured")
                return False
            
            # Validate phone number
            phone = self._format_phone_number(to_phone)
            if not phone:
                logger.error("Invalid phone number", phone=to_phone)
                return False
            
            # Send template message if template specified
            if template_name:
                success = await self._send_template_message(
                    phone, template_name, template_params or []
                )
            else:
                # Send regular text message
                success = await self._send_text_message(phone, message)
            
            if success:
                logger.info("WhatsApp message sent successfully", 
                           to=phone, 
                           template=template_name)
                
                # Record success metrics
                metrics.increment_counter("whatsapp_sent_total", labels={"status": "success"})
            else:
                # Record failure metrics
                metrics.increment_counter("whatsapp_sent_total", labels={"status": "failed"})
            
            return success
            
        except Exception as e:
            logger.error("Failed to send WhatsApp message", 
                        to=to_phone, 
                        error=str(e))
            
            # Record failure metrics
            metrics.increment_counter("whatsapp_sent_total", labels={"status": "failed"})
            
            return False
    
    async def send_bulk_messages(
        self,
        recipients: List[str],
        message: str,
        template_name: Optional[str] = None,
        batch_size: int = 20
    ) -> Dict[str, Any]:
        """
        Send bulk WhatsApp messages with rate limiting
        
        Args:
            recipients: List of recipient phone numbers
            message: Message text
            template_name: WhatsApp template name (optional)
            batch_size: Number of messages to send per batch
        
        Returns:
            Dict containing success/failure counts
        """
        results = {
            "total": len(recipients),
            "sent": 0,
            "failed": 0,
            "errors": []
        }
        
        try:
            # Process in batches to respect WhatsApp rate limits
            for i in range(0, len(recipients), batch_size):
                batch = recipients[i:i + batch_size]
                
                # Send messages concurrently within batch
                tasks = [
                    self.send_message(
                        to_phone=phone,
                        message=message,
                        template_name=template_name
                    )
                    for phone in batch
                ]
                
                batch_results = await asyncio.gather(*tasks, return_exceptions=True)
                
                for phone, result in zip(batch, batch_results):
                    if isinstance(result, Exception):
                        results["failed"] += 1
                        results["errors"].append({"phone": phone, "error": str(result)})
                    elif result:
                        results["sent"] += 1
                    else:
                        results["failed"] += 1
                        results["errors"].append({"phone": phone, "error": "Unknown error"})
                
                # Rate limiting delay between batches (WhatsApp has strict limits)
                if i + batch_size < len(recipients):
                    await asyncio.sleep(2.0)  # 2 second delay between batches
            
            logger.info("Bulk WhatsApp completed", 
                       total=results["total"],
                       sent=results["sent"],
                       failed=results["failed"])
            
            return results
            
        except Exception as e:
            logger.error("Bulk WhatsApp failed", error=str(e))
            results["errors"].append({"error": str(e)})
            return results
    
    async def health_check(self) -> bool:
        """
        Check if WhatsApp service is healthy
        
        Returns:
            bool: True if service is healthy
        """
        try:
            if not self.enabled:
                return True  # Service is "healthy" if disabled
            
            if not self.api_key:
                logger.warning("WhatsApp API key not configured")
                return False
            
            # Test API connectivity with a simple request
            # Parse API key (expected format: username:password for Twilio basic auth)
            if ":" not in self.api_key:
                logger.error("WhatsApp API key must be in format 'username:password'")
                return False
                
            api_parts = self.api_key.split(":", 1)  # Split on first : only
            if len(api_parts) != 2:
                logger.error("Invalid WhatsApp API key format")
                return False
                
            username, password = api_parts
            
            async with httpx.AsyncClient(timeout=10.0) as client:
                response = await client.get(
                    f"{self.base_url}/v1/Account",  # Twilio account info endpoint
                    auth=(username, password)
                )
                
                if response.status_code == 200:
                    logger.info("WhatsApp service health check passed")
                    return True
                else:
                    logger.error("WhatsApp service health check failed", 
                               status_code=response.status_code)
                    return False
            
        except Exception as e:
            logger.error("WhatsApp service health check failed", error=str(e))
            return False
    
    # ================================================================
    # PRIVATE HELPER METHODS
    # ================================================================
    
    async def _send_text_message(self, to_phone: str, message: str) -> bool:
        """Send regular text message via Twilio"""
        try:
            # Parse API credentials
            try:
                username, password = self._parse_api_credentials()
            except ValueError as e:
                logger.error(f"WhatsApp API key configuration error: {e}")
                return False
            
            # Prepare request data
            data = {
                "From": f"whatsapp:{self.from_number}",
                "To": f"whatsapp:{to_phone}",
                "Body": message
            }
            
            # Send via Twilio API
            async with httpx.AsyncClient(timeout=30.0) as client:
                response = await client.post(
                    f"{self.base_url}/2010-04-01/Accounts/{username}/Messages.json",
                    data=data,
                    auth=(username, password)
                )
                
                if response.status_code == 201:
                    response_data = response.json()
                    logger.debug("WhatsApp message sent", 
                               message_sid=response_data.get("sid"),
                               status=response_data.get("status"))
                    return True
                else:
                    logger.error("WhatsApp API error", 
                               status_code=response.status_code,
                               response=response.text)
                    return False
            
        except Exception as e:
            logger.error("Failed to send WhatsApp text message", error=str(e))
            return False
    
    async def _send_template_message(
        self, 
        to_phone: str, 
        template_name: str, 
        parameters: List[str]
    ) -> bool:
        """Send WhatsApp template message via Twilio"""
        try:
            # Parse API credentials
            try:
                username, password = self._parse_api_credentials()
            except ValueError as e:
                logger.error(f"WhatsApp API key configuration error: {e}")
                return False
            
            # Prepare template data
            content_variables = {str(i+1): param for i, param in enumerate(parameters)}
            
            data = {
                "From": f"whatsapp:{self.from_number}",
                "To": f"whatsapp:{to_phone}",
                "ContentSid": template_name,  # Template SID in Twilio
                "ContentVariables": str(content_variables) if content_variables else "{}"
            }
            
            # Send via Twilio API
            async with httpx.AsyncClient(timeout=30.0) as client:
                response = await client.post(
                    f"{self.base_url}/2010-04-01/Accounts/{username}/Messages.json",
                    data=data,
                    auth=(username, password)
                )
                
                if response.status_code == 201:
                    response_data = response.json()
                    logger.debug("WhatsApp template message sent", 
                               message_sid=response_data.get("sid"),
                               template=template_name)
                    return True
                else:
                    logger.error("WhatsApp template API error", 
                               status_code=response.status_code,
                               response=response.text,
                               template=template_name)
                    return False
            
        except Exception as e:
            logger.error("Failed to send WhatsApp template message", 
                        template=template_name, 
                        error=str(e))
            return False
    
    def _format_phone_number(self, phone: str) -> Optional[str]:
        """
        Format phone number for WhatsApp (Spanish format)
        
        Args:
            phone: Input phone number
        
        Returns:
            Formatted phone number or None if invalid
        """
        if not phone:
            return None
        
        # Remove spaces, dashes, and other non-digit characters
        clean_phone = "".join(filter(str.isdigit, phone.replace("+", "")))
        
        # Handle Spanish phone numbers
        if clean_phone.startswith("34"):
            # Already has country code
            return f"+{clean_phone}"
        elif clean_phone.startswith(("6", "7", "9")) and len(clean_phone) == 9:
            # Spanish mobile/landline without country code
            return f"+34{clean_phone}"
        elif len(clean_phone) == 9 and clean_phone[0] in "679":
            # Likely Spanish mobile
            return f"+34{clean_phone}"
        else:
            logger.warning("Unrecognized phone format", phone=phone)
            return None
    
    async def _get_message_status(self, message_sid: str) -> Optional[str]:
        """Get message delivery status from Twilio"""
        try:
            # Parse API credentials
            try:
                username, password = self._parse_api_credentials()
            except ValueError as e:
                logger.error(f"WhatsApp API key configuration error: {e}")
                return None
            
            async with httpx.AsyncClient(timeout=10.0) as client:
                response = await client.get(
                    f"{self.base_url}/2010-04-01/Accounts/{username}/Messages/{message_sid}.json",
                    auth=(username, password)
                )
                
                if response.status_code == 200:
                    data = response.json()
                    return data.get("status")
                else:
                    logger.error("Failed to get message status", 
                               message_sid=message_sid,
                               status_code=response.status_code)
                    return None
            
        except Exception as e:
            logger.error("Failed to check message status", 
                        message_sid=message_sid, 
                        error=str(e))
            return None