"""
WhatsApp Integration Service

This service handles WhatsApp messaging for invoices and other business communications
using WhatsApp Business API or Twilio WhatsApp API.
"""

import requests
import json
from typing import Optional, Dict, Any
from io import BytesIO
import base64
from datetime import datetime

from app.core.config import settings as app_settings
from app.services.document_pdf_storage import public_absolute_url
from app.services.whatsapp_settings_service import get_whatsapp_settings
from sqlalchemy.orm import Session


class WhatsAppService:
    """WhatsApp messaging service for business communications"""
    
    def __init__(self, db: Session):
        self.db = db
        self.settings = self._load_settings()
    
    def _load_settings(self) -> Dict[str, str]:
        """Load WhatsApp settings from AppSetting meta_data."""
        cfg = get_whatsapp_settings(self.db)
        if not cfg.get("twilio_whatsapp_number"):
            cfg["twilio_whatsapp_number"] = f"whatsapp:+{app_settings.whatsapp_default_number.lstrip('+')}"
        return cfg
    
    def is_enabled(self) -> bool:
        """Check if WhatsApp is enabled and configured"""
        return (
            self.settings.get('whatsapp_enabled', 'false').lower() == 'true' and
            self.settings.get('whatsapp_api_provider') and
            self._is_provider_configured()
        )
    
    def _is_provider_configured(self) -> bool:
        """Check if the selected provider is properly configured"""
        provider = self.settings.get('whatsapp_api_provider')
        
        if provider == 'twilio':
            return all([
                self.settings.get('twilio_account_sid'),
                self.settings.get('twilio_auth_token'),
                self.settings.get('twilio_whatsapp_number')
            ])
        elif provider == 'whatsapp_business':
            return all([
                self.settings.get('whatsapp_business_token'),
                self.settings.get('whatsapp_business_phone_id')
            ])
        
        return False
    
    def send_invoice(
        self,
        customer_phone: str,
        invoice_data: Dict[str, Any],
        pdf_buffer: BytesIO = None,
        document_public_url: Optional[str] = None,
        document_filename: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Send invoice via WhatsApp (text + optional document link)."""
        message = self._create_invoice_message(invoice_data)
        pdf_url = document_public_url
        if not pdf_url and pdf_buffer:
            pdf_url = getattr(pdf_buffer, "public_url", None)
        return self.send_business_document(
            phone_number=customer_phone,
            message=message,
            document_public_url=pdf_url,
            document_filename=document_filename or f"Invoice_{invoice_data.get('invoice_number', 'doc')}.pdf",
        )

    def send_business_document(
        self,
        phone_number: str,
        message: str,
        document_public_url: Optional[str] = None,
        document_filename: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Send text and optional PDF link (saved under /static/documents/)."""
        if not self.is_enabled():
            return {'success': False, 'error': 'WhatsApp service is not enabled or configured'}

        formatted_phone = self._format_phone_number(phone_number)
        if not formatted_phone:
            return {'success': False, 'error': 'Invalid phone number format'}

        provider = self.settings.get('whatsapp_api_provider')
        try:
            if provider == 'twilio':
                result = self._send_via_twilio(formatted_phone, message, None)
                if result.get('success') and document_public_url:
                    result['pdf_note'] = (
                        f'PDF saved at {document_public_url} — share link manually or configure Twilio media URL'
                    )
                return result
            if provider == 'whatsapp_business':
                result = self._send_via_whatsapp_business(formatted_phone, message, None)
                if not result.get('success'):
                    return result
                if document_public_url:
                    doc_result = self._send_whatsapp_document(
                        formatted_phone, document_public_url, document_filename
                    )
                    result['document'] = doc_result
                    if not doc_result.get('success'):
                        result['pdf_note'] = doc_result.get('error')
                return result
            return {'success': False, 'error': 'Invalid WhatsApp provider configured'}
        except Exception as e:
            return {'success': False, 'error': f'Failed to send WhatsApp message: {str(e)}'}

    def _send_whatsapp_document(
        self,
        to_number: str,
        document_url: str,
        filename: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Send document message via WhatsApp Business Cloud API."""
        token = self.settings.get('whatsapp_business_token')
        phone_id = self.settings.get('whatsapp_business_phone_id')
        if not token or not phone_id:
            return {'success': False, 'error': 'WhatsApp Business API not configured'}

        if document_url.startswith('/'):
            document_url = public_absolute_url(document_url)

        clean_number = to_number.replace('+', '')
        url = f"https://graph.facebook.com/v18.0/{phone_id}/messages"
        headers = {'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
        payload = {
            'messaging_product': 'whatsapp',
            'to': clean_number,
            'type': 'document',
            'document': {
                'link': document_url,
                'filename': filename or 'document.pdf',
            },
        }
        try:
            response = requests.post(url, headers=headers, json=payload, timeout=30)
            response.raise_for_status()
            data = response.json()
            return {
                'success': True,
                'message_id': data.get('messages', [{}])[0].get('id'),
                'document_url': document_url,
            }
        except requests.exceptions.RequestException as e:
            return {'success': False, 'error': f'Document send failed: {str(e)}'}
    
    def _format_phone_number(self, phone: str) -> Optional[str]:
        """Format phone number for WhatsApp (international format)"""
        if not phone:
            return None
        
        # Remove all non-digit characters
        clean_phone = ''.join(filter(str.isdigit, phone))
        
        # Add country code if not present (assuming Botswana +267)
        if len(clean_phone) == 8 and clean_phone.startswith(('7', '2', '3')):
            return f"+267{clean_phone}"
        elif len(clean_phone) == 11 and clean_phone.startswith('267'):
            return f"+{clean_phone}"
        elif clean_phone.startswith('+'):
            return clean_phone
        else:
            # Try to detect other formats
            if len(clean_phone) >= 10:
                return f"+{clean_phone}"
        
        return None
    
    def _create_invoice_message(self, invoice_data: Dict[str, Any]) -> str:
        """Create formatted invoice message for WhatsApp"""
        company_name = self.settings.get('company_name', 'Your Company')
        currency_symbol = self.settings.get('currency_symbol', 'P')
        
        message = f""" *INVOICE FROM {company_name.upper()}*

 *Invoice Details:*
• Invoice No: {invoice_data['invoice_number']}
• Date: {invoice_data['date']}
• Due Date: {invoice_data['due_date']}

 *Bill To:*
{invoice_data['customer_name']}

 *Amount Summary:*
• Subtotal: {currency_symbol}{invoice_data['subtotal']:.2f}
• VAT: {currency_symbol}{invoice_data['vat_amount']:.2f}
• *Total: {currency_symbol}{invoice_data['total_amount']:.2f}*

 *Payment Terms:* {invoice_data['payment_terms']} days

Thank you for your business! 

---
{company_name}
 {self.settings.get('company_phone', '')}
 {self.settings.get('company_email', '')}"""

        return message
    
    def _send_via_twilio(
        self, 
        to_number: str, 
        message: str, 
        pdf_buffer: BytesIO = None
    ) -> Dict[str, Any]:
        """Send message via Twilio WhatsApp API"""
        from twilio.rest import Client
        
        account_sid = self.settings.get('twilio_account_sid')
        auth_token = self.settings.get('twilio_auth_token')
        from_number = self.settings.get('twilio_whatsapp_number')
        
        client = Client(account_sid, auth_token)
        
        try:
            # Send text message
            message_obj = client.messages.create(
                body=message,
                from_=f"whatsapp:{from_number}",
                to=f"whatsapp:{to_number}"
            )
            
            result = {
                'success': True,
                'message_sid': message_obj.sid,
                'status': message_obj.status
            }
            
            # Send PDF if provided
            if pdf_buffer:
                # Upload PDF to a temporary URL or send as media
                # Note: Twilio requires a publicly accessible URL for media
                # In production, you'd upload to cloud storage first
                result['pdf_note'] = 'PDF attachment requires public URL setup'
            
            return result
            
        except Exception as e:
            return {
                'success': False,
                'error': f'Twilio error: {str(e)}'
            }
    
    def _send_via_whatsapp_business(
        self, 
        to_number: str, 
        message: str, 
        pdf_buffer: BytesIO = None
    ) -> Dict[str, Any]:
        """Send message via WhatsApp Business API"""
        token = self.settings.get('whatsapp_business_token')
        phone_id = self.settings.get('whatsapp_business_phone_id')
        
        url = f"https://graph.facebook.com/v18.0/{phone_id}/messages"
        
        headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }
        
        # Remove + from phone number for WhatsApp Business API
        clean_number = to_number.replace('+', '')
        
        payload = {
            'messaging_product': 'whatsapp',
            'to': clean_number,
            'type': 'text',
            'text': {
                'body': message
            }
        }
        
        try:
            response = requests.post(url, headers=headers, json=payload)
            response.raise_for_status()
            
            result_data = response.json()
            
            return {
                'success': True,
                'message_id': result_data.get('messages', [{}])[0].get('id'),
                'status': 'sent'
            }
            
        except requests.exceptions.RequestException as e:
            return {
                'success': False,
                'error': f'WhatsApp Business API error: {str(e)}'
            }
    
    def send_custom_message(
        self, 
        phone_number: str, 
        message: str
    ) -> Dict[str, Any]:
        """Send custom WhatsApp message"""
        
        if not self.is_enabled():
            return {
                'success': False,
                'error': 'WhatsApp service is not enabled or configured'
            }
        
        formatted_phone = self._format_phone_number(phone_number)
        if not formatted_phone:
            return {
                'success': False,
                'error': 'Invalid phone number format'
            }
        
        provider = self.settings.get('whatsapp_api_provider')
        
        try:
            if provider == 'twilio':
                return self._send_via_twilio(formatted_phone, message)
            elif provider == 'whatsapp_business':
                return self._send_via_whatsapp_business(formatted_phone, message)
            else:
                return {
                    'success': False,
                    'error': 'Invalid WhatsApp provider configured'
                }
                
        except Exception as e:
            return {
                'success': False,
                'error': f'Failed to send WhatsApp message: {str(e)}'
            }
    
    def get_message_status(self, message_id: str) -> Dict[str, Any]:
        """Get status of a sent message"""
        provider = self.settings.get('whatsapp_api_provider')
        
        if provider == 'twilio':
            return self._get_twilio_message_status(message_id)
        elif provider == 'whatsapp_business':
            return self._get_whatsapp_business_status(message_id)
        else:
            return {
                'success': False,
                'error': 'Invalid provider'
            }
    
    def _get_twilio_message_status(self, message_sid: str) -> Dict[str, Any]:
        """Get message status from Twilio"""
        try:
            from twilio.rest import Client
            
            account_sid = self.settings.get('twilio_account_sid')
            auth_token = self.settings.get('twilio_auth_token')
            
            client = Client(account_sid, auth_token)
            message = client.messages(message_sid).fetch()
            
            return {
                'success': True,
                'status': message.status,
                'error_code': message.error_code,
                'error_message': message.error_message
            }
            
        except Exception as e:
            return {
                'success': False,
                'error': str(e)
            }
    
    def _get_whatsapp_business_status(self, message_id: str) -> Dict[str, Any]:
        """Get message status from WhatsApp Business API"""
        # WhatsApp Business API doesn't provide direct message status lookup
        # Status updates come via webhooks
        return {
            'success': True,
            'status': 'sent',
            'note': 'Status tracking requires webhook setup'
        }
    
    def test_connection(self) -> Dict[str, Any]:
        """Test WhatsApp API connection"""
        if not self.is_enabled():
            return {
                'success': False,
                'error': 'WhatsApp service is not enabled or configured'
            }
        
        provider = self.settings.get('whatsapp_api_provider')
        
        if provider == 'twilio':
            return self._test_twilio_connection()
        elif provider == 'whatsapp_business':
            return self._test_whatsapp_business_connection()
        else:
            return {
                'success': False,
                'error': 'Invalid provider'
            }
    
    def _test_twilio_connection(self) -> Dict[str, Any]:
        """Test Twilio connection"""
        try:
            from twilio.rest import Client
            
            account_sid = self.settings.get('twilio_account_sid')
            auth_token = self.settings.get('twilio_auth_token')
            
            client = Client(account_sid, auth_token)
            account = client.api.accounts(account_sid).fetch()
            
            return {
                'success': True,
                'provider': 'twilio',
                'account_sid': account.sid,
                'status': account.status
            }
            
        except Exception as e:
            return {
                'success': False,
                'error': f'Twilio connection failed: {str(e)}'
            }
    
    def _test_whatsapp_business_connection(self) -> Dict[str, Any]:
        """Test WhatsApp Business API connection"""
        try:
            token = self.settings.get('whatsapp_business_token')
            phone_id = self.settings.get('whatsapp_business_phone_id')
            
            url = f"https://graph.facebook.com/v18.0/{phone_id}"
            headers = {
                'Authorization': f'Bearer {token}'
            }
            
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            
            data = response.json()
            
            return {
                'success': True,
                'provider': 'whatsapp_business',
                'phone_id': phone_id,
                'verified_name': data.get('verified_name'),
                'display_phone_number': data.get('display_phone_number')
            }
            
        except Exception as e:
            return {
                'success': False,
                'error': f'WhatsApp Business API connection failed: {str(e)}'
            }


def get_whatsapp_service(db: Session) -> WhatsAppService:
    """Factory function to get WhatsAppService instance"""
    return WhatsAppService(db)
