
import logging
import smtplib
from typing import Tuple, Dict, Any, Optional
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from django.conf import settings
from django.core.mail import get_connection, EmailMultiAlternatives
from django.template import Template, Context
from django.utils import timezone
from django.db import transaction
from .models import EmailLog, NotificationTemplate
from settings.models import SystemSettings, CompanyProfile

logger = logging.getLogger(__name__)

class EmailService:
    """Enhanced email service with complete settings integration and logging"""
    
    def __init__(self):
        self.email_settings = self._load_email_settings()
        self.company_profile = self._load_company_profile()
        self._validate_settings()

    def _load_email_settings(self) -> Dict[str, Any]:
        """Load email settings from SystemSettings model with fallbacks"""
        default_settings = {
            'HOST': getattr(settings, 'EMAIL_HOST', 'mail.optinet.co.ke'),
            'PORT': getattr(settings, 'EMAIL_PORT', 587),
            'HOST_USER': getattr(settings, 'EMAIL_HOST_USER', ''),
            'HOST_PASSWORD': getattr(settings, 'EMAIL_HOST_PASSWORD', ''),
            'USE_TLS': getattr(settings, 'EMAIL_USE_TLS', True),
            'USE_SSL': getattr(settings, 'EMAIL_USE_SSL', False),
            'DEFAULT_FROM_EMAIL': getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@optinet.co.ke'),
            'TIMEOUT': 30
        }
        
        try:
            # Get email settings from database
            email_settings = SystemSettings.objects.filter(category='email')
            db_settings = {}
            
            for setting in email_settings:
                key = setting.key.upper()
                value = setting.value
                
                # Convert string values to appropriate types
                if key in ['PORT', 'TIMEOUT']:
                    try:
                        value = int(value)
                    except (ValueError, TypeError):
                        value = default_settings.get(key, 587)
                elif key in ['USE_TLS', 'USE_SSL']:
                    value = value.lower() in ['true', '1', 'yes', 'on']
                
                db_settings[key] = value
            
            # Merge with defaults
            final_settings = {**default_settings, **db_settings}
            
            logger.info(f"Email settings loaded: HOST={final_settings['HOST']}, PORT={final_settings['PORT']}, USE_TLS={final_settings['USE_TLS']}")
            return final_settings
            
        except Exception as e:
            logger.error(f"Error loading email settings from database: {e}")
            logger.info("Using default email settings from Django settings")
            return default_settings

    def _load_company_profile(self) -> Optional[CompanyProfile]:
        """Load company profile for email templates"""
        try:
            return CompanyProfile.objects.first()
        except Exception as e:
            logger.error(f"Error loading company profile: {e}")
            return None

    def _validate_settings(self) -> Tuple[bool, str]:
        """Validate email configuration"""
        errors = []
        
        if not self.email_settings.get('HOST'):
            errors.append("SMTP host is required")
        
        if not self.email_settings.get('HOST_USER'):
            errors.append("SMTP username/email is required")
        
        if not self.email_settings.get('HOST_PASSWORD'):
            errors.append("SMTP password is required")
        
        port = self.email_settings.get('PORT', 587)
        if not isinstance(port, int) or port <= 0:
            errors.append("Valid SMTP port is required")
        
        if errors:
            error_msg = "; ".join(errors)
            logger.error(f"Email settings validation failed: {error_msg}")
            return False, error_msg
        
        return True, "Settings valid"

    def _get_template_context(self, extra_context: Dict[str, Any] = None) -> Dict[str, Any]:
        """Get template context with company info and extra variables"""
        context = {
            'company_name': 'OptiNet Solutions',
            'company_email': '',
            'company_phone': '',
            'company_website': '',
            'company_address': '',
            'current_year': timezone.now().year,
            'current_date': timezone.now().strftime('%Y-%m-%d'),
            'current_datetime': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
        }
        
        if self.company_profile:
            context.update({
                'company_name': self.company_profile.company_name or context['company_name'],
                'company_email': self.company_profile.email or '',
                'company_phone': self.company_profile.phone or '',
                'company_website': self.company_profile.website or '',
                'company_address': self.company_profile.address or '',
            })
        
        if extra_context:
            context.update(extra_context)
        
        return context

    def _render_template(self, template_string: str, context: Dict[str, Any]) -> str:
        """Render Django template string with context"""
        try:
            template = Template(template_string)
            django_context = Context(context)
            return template.render(django_context)
        except Exception as e:
            logger.error(f"Error rendering template: {e}")
            return template_string

    def _create_html_email_content(self, subject: str, plain_content: str, context: Dict[str, Any]) -> str:
        """Create professional HTML email content"""
        
        # Render plain content with context
        rendered_content = self._render_template(plain_content, context)
        
        # Convert line breaks to HTML
        html_content = rendered_content.replace('\n', '<br>')
        
        # Professional email template
        html_template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{subject}</title>
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }}
        .email-container {{
            max-width: 600px;
            margin: 20px auto;
            background-color: #ffffff;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }}
        .email-header {{
            background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }}
        .email-header h1 {{
            margin: 0;
            font-size: 24px;
            font-weight: 600;
        }}
        .email-body {{
            padding: 30px;
        }}
        .email-content {{
            margin-bottom: 20px;
        }}
        .button {{
            display: inline-block;
            background-color: #007bff;
            color: white;
            padding: 12px 24px;
            text-decoration: none;
            border-radius: 5px;
            font-weight: 500;
            margin: 10px 0;
        }}
        .button:hover {{
            background-color: #0056b3;
        }}
        .info-box {{
            background-color: #e7f3ff;
            border-left: 4px solid #007bff;
            padding: 15px;
            margin: 20px 0;
            border-radius: 0 4px 4px 0;
        }}
        .success-box {{
            background-color: #d4edda;
            border-left: 4px solid #28a745;
            padding: 15px;
            margin: 20px 0;
            border-radius: 0 4px 4px 0;
        }}
        .warning-box {{
            background-color: #fff3cd;
            border-left: 4px solid #ffc107;
            padding: 15px;
            margin: 20px 0;
            border-radius: 0 4px 4px 0;
        }}
        .email-footer {{
            background-color: #f8f9fa;
            padding: 20px 30px;
            text-align: center;
            color: #6c757d;
            font-size: 14px;
            border-top: 1px solid #e9ecef;
        }}
        .footer-info {{
            margin: 5px 0;
        }}
        .disclaimer {{
            margin-top: 15px;
            font-size: 12px;
            color: #999;
        }}
    </style>
</head>
<body>
    <div class="email-container">
        <div class="email-header">
            <h1>{context.get('company_name', 'OptiNet Solutions')}</h1>
        </div>
        <div class="email-body">
            <div class="email-content">
                {html_content}
            </div>
        </div>
        <div class="email-footer">
            <div class="footer-info"><strong>{context.get('company_name', 'OptiNet Solutions')}</strong></div>
            {f'<div class="footer-info">Email: {context.get("company_email")}</div>' if context.get('company_email') else ''}
            {f'<div class="footer-info">Phone: {context.get("company_phone")}</div>' if context.get('company_phone') else ''}
            {f'<div class="footer-info">Website: {context.get("company_website")}</div>' if context.get('company_website') else ''}
            <div class="footer-info">&copy; {context.get('current_year')} {context.get('company_name', 'OptiNet Solutions')}. All rights reserved.</div>
            <div class="disclaimer">
                This is an automated email. Please do not reply to this message.
            </div>
        </div>
    </div>
</body>
</html>
        """
        
        return html_template

    def _create_email_log(self, recipient_email: str, subject: str, content: str, 
                         email_type: str = 'general', recipient_name: str = '',
                         sent_by=None, **kwargs) -> EmailLog:
        """Create email log entry"""
        return EmailLog.objects.create(
            recipient_email=recipient_email,
            recipient_name=recipient_name,
            subject=subject,
            message=content,
            email_type=email_type,
            sent_by=sent_by,
            status='pending',
            customer_id=kwargs.get('customer_id'),
            employee_id=kwargs.get('employee_id'),
            invoice_id=kwargs.get('invoice_id'),
            payment_id=kwargs.get('payment_id'),
        )

    def send_email(self, recipient_email: str, subject: str, content: str,
                  email_type: str = 'general', recipient_name: str = '',
                  sent_by=None, context_data: Dict[str, Any] = None,
                  template_type: str = None, **kwargs) -> Tuple[bool, str]:
        """Send email with comprehensive error handling and logging"""
        
        # Initialize context
        if context_data is None:
            context_data = {}
        
        # Get template if specified
        if template_type:
            try:
                template = NotificationTemplate.objects.get(
                    template_type=template_type,
                    is_active=True
                )
                subject = template.subject or subject
                content = template.content
            except NotificationTemplate.DoesNotExist:
                logger.warning(f"Template {template_type} not found, using provided content")
        
        # Prepare context
        full_context = self._get_template_context(context_data)
        
        # Render subject and content
        rendered_subject = self._render_template(subject, full_context)
        rendered_content = self._render_template(content, full_context)
        
        # Create email log
        email_log = self._create_email_log(
            recipient_email=recipient_email,
            subject=rendered_subject,
            content=rendered_content,
            email_type=email_type,
            recipient_name=recipient_name,
            sent_by=sent_by,
            **kwargs
        )
        
        try:
            # Validate settings first
            settings_valid, validation_error = self._validate_settings()
            if not settings_valid:
                email_log.status = 'failed'
                email_log.error_message = f"Settings validation failed: {validation_error}"
                email_log.save()
                return False, validation_error
            
            # Create HTML version
            html_content = self._create_html_email_content(rendered_subject, rendered_content, full_context)
            
            # Configure SSL/TLS based on settings and port
            port = self.email_settings['PORT']
            use_ssl = self.email_settings.get('USE_SSL', False)
            use_tls = self.email_settings.get('USE_TLS', True)
            
            # Handle explicit SSL/TLS configuration first
            if 'USE_SSL' in self.email_settings:
                use_ssl = bool(self.email_settings['USE_SSL'])
                use_tls = False if use_ssl else bool(self.email_settings.get('USE_TLS', False))
            elif 'USE_TLS' in self.email_settings:
                use_tls = bool(self.email_settings['USE_TLS'])
                use_ssl = False if use_tls else False
            else:
                # Auto-configure based on common port conventions only if not explicitly set
                if port == 465:
                    # Port 465 typically uses implicit SSL
                    use_ssl = True
                    use_tls = False
                elif port == 587:
                    # Port 587 typically uses STARTTLS
                    use_ssl = False
                    use_tls = True
                elif port == 25:
                    # Port 25 typically uses no encryption or STARTTLS
                    use_ssl = False
                    use_tls = False
                else:
                    # For custom ports, default to TLS
                    use_ssl = False
                    use_tls = True
            
            # Create email connection
            connection = get_connection(
                host=self.email_settings['HOST'],
                port=port,
                username=self.email_settings['HOST_USER'],
                password=self.email_settings['HOST_PASSWORD'],
                use_tls=use_tls,
                use_ssl=use_ssl,
                timeout=self.email_settings.get('TIMEOUT', 30),
                fail_silently=False,
            )
            
            # Create email message
            email_message = EmailMultiAlternatives(
                subject=rendered_subject,
                body=rendered_content,  # Plain text version
                from_email=self.email_settings.get('DEFAULT_FROM_EMAIL'),
                to=[recipient_email],
                connection=connection
            )
            
            # Attach HTML version
            email_message.attach_alternative(html_content, "text/html")
            
            # Send email
            result = email_message.send()
            
            if result:
                email_log.status = 'sent'
                email_log.save()
                logger.info(f"Email sent successfully to {recipient_email} with subject: {rendered_subject}")
                return True, "Email sent successfully"
            else:
                email_log.status = 'failed'
                email_log.error_message = "Email send returned 0 - possible configuration issue"
                email_log.save()
                return False, "Email send failed - check SMTP configuration"
        
        except smtplib.SMTPAuthenticationError as e:
            error_msg = f"SMTP Authentication failed: {str(e)}. Check your email credentials."
            email_log.status = 'failed'
            email_log.error_message = error_msg
            email_log.save()
            logger.error(f"SMTP Auth error for {recipient_email}: {e}")
            return False, error_msg
        
        except smtplib.SMTPConnectError as e:
            error_msg = f"Cannot connect to SMTP server {self.email_settings['HOST']}:{self.email_settings['PORT']}. Check host and port."
            email_log.status = 'failed'
            email_log.error_message = error_msg
            email_log.save()
            logger.error(f"SMTP Connect error: {e}")
            return False, error_msg
        
        except Exception as e:
            error_str = str(e).lower()
            if 'wrong version number' in error_str or 'ssl' in error_str:
                error_msg = f"SSL/TLS configuration error: {str(e)}. Try different SSL/TLS settings or check if the server supports the configured encryption method."
                logger.error(f"SSL/TLS configuration error for port {self.email_settings['PORT']}: use_ssl={use_ssl}, use_tls={use_tls}")
            else:
                error_msg = f"Unexpected error sending email: {str(e)}"
            
            email_log.status = 'failed'
            email_log.error_message = error_msg
            email_log.save()
            logger.error(f"Email sending error: {e}")
            return False, error_msg
        
        except smtplib.SMTPRecipientsRefused as e:
            error_msg = f"Recipient {recipient_email} was refused by server: {str(e)}"
            email_log.status = 'failed'
            email_log.error_message = error_msg
            email_log.save()
            logger.error(f"SMTP Recipients refused: {e}")
            return False, error_msg
        
        except smtplib.SMTPServerDisconnected as e:
            error_msg = f"SMTP server disconnected unexpectedly: {str(e)}"
            email_log.status = 'failed'
            email_log.error_message = error_msg
            email_log.save()
            logger.error(f"SMTP Server disconnected: {e}")
            return False, error_msg
        
        

    def test_smtp_connection(self) -> Tuple[bool, str]:
        """Test SMTP connection with different SSL/TLS configurations"""
        port = self.email_settings['PORT']
        host = self.email_settings['HOST']
        username = self.email_settings['HOST_USER']
        password = self.email_settings['HOST_PASSWORD']
        
        # Test configurations to try
        test_configs = []
        
        if port == 587:
            test_configs = [
                {'use_ssl': False, 'use_tls': True, 'desc': 'STARTTLS (recommended for port 587)'},
                {'use_ssl': False, 'use_tls': False, 'desc': 'No encryption'},
            ]
        elif port == 465:
            test_configs = [
                {'use_ssl': True, 'use_tls': False, 'desc': 'Implicit SSL (recommended for port 465)'},
                {'use_ssl': False, 'use_tls': True, 'desc': 'STARTTLS'},
            ]
        elif port == 25:
            test_configs = [
                {'use_ssl': False, 'use_tls': False, 'desc': 'No encryption (port 25)'},
                {'use_ssl': False, 'use_tls': True, 'desc': 'STARTTLS'},
            ]
        else:
            test_configs = [
                {'use_ssl': False, 'use_tls': True, 'desc': 'STARTTLS'},
                {'use_ssl': True, 'use_tls': False, 'desc': 'Implicit SSL'},
                {'use_ssl': False, 'use_tls': False, 'desc': 'No encryption'},
            ]
        
        for config in test_configs:
            try:
                logger.info(f"Testing {config['desc']} on {host}:{port}")
                
                connection = get_connection(
                    host=host,
                    port=port,
                    username=username,
                    password=password,
                    use_tls=config['use_tls'],
                    use_ssl=config['use_ssl'],
                    timeout=10,
                    fail_silently=False,
                )
                
                # Try to open and close connection
                connection.open()
                connection.close()
                
                success_msg = f"✅ Connection successful with {config['desc']}"
                logger.info(success_msg)
                return True, success_msg
                
            except Exception as e:
                logger.warning(f"❌ Failed with {config['desc']}: {e}")
                continue
        
        return False, "❌ All SSL/TLS configurations failed. Check your SMTP server settings."

    def send_test_email(self, recipient_email: str, sent_by=None) -> Tuple[bool, str]:
        """Send a comprehensive test email"""
        subject = "Test Email from {{company_name}} - Configuration Verification"
        
        content = """
<div class="success-box">
    <h2>✅ Email Configuration Test Successful!</h2>
    <p>Congratulations! Your email system is working correctly.</p>
</div>

<h3>Test Details:</h3>
<div class="info-box">
    <ul>
        <li><strong>Recipient:</strong> {recipient_email}</li>
        <li><strong>SMTP Server:</strong> {smtp_host}:{smtp_port}</li>
        <li><strong>Encryption:</strong> {encryption_type}</li>
        <li><strong>Test Time:</strong> {test_time}</li>
        <li><strong>Sent By:</strong> {sent_by_name}</li>
    </ul>
</div>

<h3>System Information:</h3>
<p>Your {{{{company_name}}}} management system is successfully configured to send emails through your custom SMTP server.</p>

<div class="info-box">
    <h4>What this means:</h4>
    <ul>
        <li>Invoice notifications will be delivered</li>
        <li>Payment confirmations will be sent</li>
        <li>Password reset emails will work</li>
        <li>System notifications are operational</li>
    </ul>
</div>

<p>If you have any questions about your email configuration, please contact your system administrator.</p>
        """.format(
            recipient_email=recipient_email,
            smtp_host=self.email_settings['HOST'],
            smtp_port=self.email_settings['PORT'],
            encryption_type='TLS' if self.email_settings.get('USE_TLS') else 'SSL' if self.email_settings.get('USE_SSL') else 'None',
            test_time=timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
            sent_by_name=sent_by.get_full_name() if sent_by else 'System Administrator'
        )
        
        return self.send_email(
            recipient_email=recipient_email,
            subject=subject,
            content=content,
            email_type='test_email',
            recipient_name='Test User',
            sent_by=sent_by
        )

    def get_email_stats(self) -> Dict[str, int]:
        """Get email statistics"""
        return {
            'total_sent': EmailLog.objects.filter(status='sent').count(),
            'total_failed': EmailLog.objects.filter(status='failed').count(),
            'total_pending': EmailLog.objects.filter(status='pending').count(),
            'today_sent': EmailLog.objects.filter(
                status='sent',
                sent_at__date=timezone.now().date()
            ).count(),
        }

# Global email service instance
email_service = EmailService()
