import smtplib
import ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import formataddr
from sqlalchemy.orm import Session
from typing import Optional, List
from datetime import datetime
from database import SMTPConfig, EmailLog, User
from schemas import EmailSend, EmailResponse
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class EmailService:
    def __init__(self, db: Session):
        self.db = db
    
    def get_user_smtp_config(self, user_id: int, config_id: Optional[int] = None) -> Optional[SMTPConfig]:
        """Get SMTP configuration for user"""
        if config_id:
            return self.db.query(SMTPConfig).filter(
                SMTPConfig.id == config_id,
                SMTPConfig.user_id == user_id,
                SMTPConfig.is_active == True
            ).first()
        
        # Return default config
        return self.db.query(SMTPConfig).filter(
            SMTPConfig.user_id == user_id,
            SMTPConfig.is_default == True,
            SMTPConfig.is_active == True
        ).first()
    
    def get_all_user_smtp_configs(self, user_id: int) -> List[SMTPConfig]:
        """Get all SMTP configurations for a user"""
        return self.db.query(SMTPConfig).filter(
            SMTPConfig.user_id == user_id
        ).all()
    
    def create_smtp_config(self, user_id: int, config_data: dict) -> SMTPConfig:
        """Create a new SMTP configuration"""
        # If this is the first config or marked as default, handle default status
        if config_data.get('is_default'):
            self.db.query(SMTPConfig).filter(
                SMTPConfig.user_id == user_id
            ).update({"is_default": False})
        
        # Check if this is the first config
        existing_count = self.db.query(SMTPConfig).filter(
            SMTPConfig.user_id == user_id
        ).count()
        
        if existing_count == 0:
            config_data['is_default'] = True
        
        db_config = SMTPConfig(
            user_id=user_id,
            name=config_data['name'],
            host=config_data['host'],
            port=config_data['port'],
            username=config_data['username'],
            password=config_data['password'],
            use_tls=config_data.get('use_tls', True),
            is_default=config_data.get('is_default', False),
            is_active=True
        )
        
        self.db.add(db_config)
        self.db.commit()
        self.db.refresh(db_config)
        return db_config
    
    def update_smtp_config(self, config_id: int, user_id: int, config_data: dict) -> Optional[SMTPConfig]:
        """Update an existing SMTP configuration"""
        config = self.db.query(SMTPConfig).filter(
            SMTPConfig.id == config_id,
            SMTPConfig.user_id == user_id
        ).first()
        
        if not config:
            return None
        
        # Handle default status change
        if config_data.get('is_default') and not config.is_default:
            self.db.query(SMTPConfig).filter(
                SMTPConfig.user_id == user_id
            ).update({"is_default": False})
        
        # Update fields
        for field, value in config_data.items():
            if value is not None:
                setattr(config, field, value)
        
        config.updated_at = datetime.utcnow()
        self.db.commit()
        self.db.refresh(config)
        return config
    
    def delete_smtp_config(self, config_id: int, user_id: int) -> bool:
        """Delete an SMTP configuration"""
        config = self.db.query(SMTPConfig).filter(
            SMTPConfig.id == config_id,
            SMTPConfig.user_id == user_id
        ).first()
        
        if not config:
            return False
        
        self.db.delete(config)
        self.db.commit()
        return True
    
    def send_email(
        self,
        user_id: int,
        email_data: EmailSend,
        smtp_config: Optional[SMTPConfig] = None
    ) -> EmailResponse:
        """Send an email using SMTP"""
        
        # Get SMTP config if not provided
        if not smtp_config:
            smtp_config = self.get_user_smtp_config(user_id)
        
        if not smtp_config:
            # Log failed attempt
            self._log_email(user_id, None, "", email_data.to_email, email_data.subject, "failed", "No SMTP configuration found")
            return EmailResponse(
                success=False,
                message="No SMTP configuration found. Please configure your SMTP settings first."
            )
        
        try:
            # Create message
            msg = MIMEMultipart('alternative')
            msg['Subject'] = email_data.subject
            msg['From'] = formataddr((email_data.from_name or smtp_config.username, smtp_config.username))
            msg['To'] = email_data.to_email
            
            # Attach body
            content_type = 'html' if email_data.is_html else 'plain'
            msg.attach(MIMEText(email_data.body, content_type, 'utf-8'))
            
            # Connect to SMTP server
            context = ssl.create_default_context()
            
            with smtplib.SMTP(smtp_config.host, smtp_config.port) as server:
                if smtp_config.use_tls:
                    server.starttls(context=context)
                
                server.login(smtp_config.username, smtp_config.password)
                server.send_message(msg)
            
            # Log successful email
            self._log_email(
                user_id, None, smtp_config.username, email_data.to_email,
                email_data.subject, "sent", None
            )
            
            logger.info(f"Email sent successfully from {smtp_config.username} to {email_data.to_email}")
            
            return EmailResponse(
                success=True,
                message="Email sent successfully"
            )
            
        except smtplib.SMTPAuthenticationError as e:
            error_msg = "SMTP authentication failed. Please check your credentials."
            self._log_email(user_id, None, smtp_config.username, email_data.to_email, email_data.subject, "failed", error_msg)
            logger.error(f"SMTP Authentication Error: {str(e)}")
            return EmailResponse(success=False, message=error_msg)
            
        except smtplib.SMTPConnectError as e:
            error_msg = "Could not connect to SMTP server. Please check your settings."
            self._log_email(user_id, None, smtp_config.username, email_data.to_email, email_data.subject, "failed", error_msg)
            logger.error(f"SMTP Connection Error: {str(e)}")
            return EmailResponse(success=False, message=error_msg)
            
        except Exception as e:
            error_msg = f"Failed to send email: {str(e)}"
            self._log_email(user_id, None, smtp_config.username, email_data.to_email, email_data.subject, "failed", error_msg)
            logger.error(f"Email sending error: {str(e)}")
            return EmailResponse(success=False, message=error_msg)
    
    def send_email_with_api_key(
        self,
        api_key_record,
        email_data: dict
    ) -> EmailResponse:
        """Send an email using API key authentication"""
        user_id = api_key_record.user_id
        
        # Get user's default SMTP config
        smtp_config = self.get_user_smtp_config(user_id)
        
        if not smtp_config:
            self._log_email(
                user_id, api_key_record.id, "", email_data['to_email'],
                email_data['subject'], "failed", "No SMTP configuration found"
            )
            return EmailResponse(
                success=False,
                message="No SMTP configuration found for this API key"
            )
        
        # Override from_email if provided
        from_email = email_data.get('from_email') or smtp_config.username
        
        try:
            # Create message
            msg = MIMEMultipart('alternative')
            msg['Subject'] = email_data['subject']
            msg['From'] = formataddr((email_data.get('from_name', ''), from_email))
            msg['To'] = email_data['to_email']
            
            # Attach body
            is_html = email_data.get('is_html', False)
            content_type = 'html' if is_html else 'plain'
            msg.attach(MIMEText(email_data['body'], content_type, 'utf-8'))
            
            # Connect to SMTP server
            context = ssl.create_default_context()
            
            with smtplib.SMTP(smtp_config.host, smtp_config.port) as server:
                if smtp_config.use_tls:
                    server.starttls(context=context)
                
                server.login(smtp_config.username, smtp_config.password)
                server.send_message(msg)
            
            # Log successful email
            self._log_email(
                user_id, api_key_record.id, from_email, email_data['to_email'],
                email_data['subject'], "sent", None
            )
            
            logger.info(f"API Email sent from {from_email} to {email_data['to_email']}")
            
            return EmailResponse(
                success=True,
                message="Email sent successfully"
            )
            
        except Exception as e:
            error_msg = f"Failed to send email: {str(e)}"
            self._log_email(
                user_id, api_key_record.id, from_email, email_data['to_email'],
                email_data['subject'], "failed", error_msg
            )
            logger.error(f"API Email error: {str(e)}")
            return EmailResponse(success=False, message=error_msg)
    
    def _log_email(
        self,
        user_id: int,
        api_key_id: Optional[int],
        from_email: str,
        to_email: str,
        subject: str,
        status: str,
        error_message: Optional[str]
    ):
        """Log email to database"""
        log = EmailLog(
            user_id=user_id,
            api_key_id=api_key_id,
            from_email=from_email,
            to_email=to_email,
            subject=subject,
            status=status,
            error_message=error_message
        )
        self.db.add(log)
        self.db.commit()
    
    def get_email_logs(self, user_id: int, limit: int = 50) -> List[EmailLog]:
        """Get email logs for a user"""
        return self.db.query(EmailLog).filter(
            EmailLog.user_id == user_id
        ).order_by(EmailLog.sent_at.desc()).limit(limit).all()
    
    def get_email_stats(self, user_id: int) -> dict:
        """Get email statistics for a user"""
        total_sent = self.db.query(EmailLog).filter(
            EmailLog.user_id == user_id,
            EmailLog.status == "sent"
        ).count()
        
        total_failed = self.db.query(EmailLog).filter(
            EmailLog.user_id == user_id,
            EmailLog.status == "failed"
        ).count()
        
        # Today's emails
        today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
        today_sent = self.db.query(EmailLog).filter(
            EmailLog.user_id == user_id,
            EmailLog.status == "sent",
            EmailLog.sent_at >= today
        ).count()
        
        return {
            "total_sent": total_sent,
            "total_failed": total_failed,
            "today_sent": today_sent,
            "success_rate": round((total_sent / (total_sent + total_failed)) * 100, 2) if (total_sent + total_failed) > 0 else 0
        }
