"""
Mail Aggregator SMTP — email sending via SMTP.

Extracted from aggregator.py for modularity.
"""

import logging
import smtplib
from typing import Optional, List, Dict, Any
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

from .mail_db import get_email_account
from .models import EmailComposeRequest, EmailSendResult

logger = logging.getLogger(__name__)


class SMTPConnectionError(Exception):
    """Raised when SMTP connection fails."""
    pass


class SMTPMixin:
    """SMTP-related methods for MailAggregator.

    Provides SMTP connection testing and email sending.
    Must be mixed into a class that has ``_credentials_service``.
    """

    async def test_smtp_connection(
        self,
        smtp_host: str,
        smtp_port: int,
        smtp_ssl: bool,
        email_address: str,
        password: str,
    ) -> tuple:
        """Test SMTP connection. Returns (success, error)."""
        try:
            if smtp_ssl:
                smtp = smtplib.SMTP_SSL(smtp_host, smtp_port)
            else:
                smtp = smtplib.SMTP(smtp_host, smtp_port)
                smtp.starttls()

            smtp.login(email_address, password)
            smtp.quit()
            return True, None

        except Exception as e:
            logger.warning(f"SMTP test failed for {email_address}: {e}")
            return False, f"SMTP Error: {str(e)}"

    async def send_email(
        self,
        account_id: str,
        user_id: str,
        request: EmailComposeRequest,
    ) -> EmailSendResult:
        """
        Send an email via SMTP.

        Args:
            account_id: The account to send from
            user_id: The user ID
            request: The compose request with recipients and content

        Returns:
            EmailSendResult with success status
        """
        account = await get_email_account(account_id, user_id)
        if not account:
            return EmailSendResult(success=False, error="Account not found")

        # Verify the account_id matches
        if request.account_id != account_id:
            return EmailSendResult(success=False, error="Account mismatch")

        # Get credentials
        vault_path = account.get("vault_path", "")
        creds = await self._credentials_service.get_credentials(account_id, vault_path)
        if not creds:
            return EmailSendResult(success=False, error="Credentials not found")

        try:
            # Create message
            if request.is_html:
                msg = MIMEMultipart("alternative")
                msg.attach(MIMEText(request.body, "html"))
            else:
                msg = MIMEText(request.body, "plain")

            msg["Subject"] = request.subject
            msg["From"] = account["email"]
            msg["To"] = ", ".join(request.to)

            if request.cc:
                msg["Cc"] = ", ".join(request.cc)

            if request.reply_to_message_id:
                msg["In-Reply-To"] = request.reply_to_message_id
                msg["References"] = request.reply_to_message_id

            # Send via SMTP
            if account["smtp_ssl"]:
                smtp = smtplib.SMTP_SSL(account["smtp_host"], account["smtp_port"])
            else:
                smtp = smtplib.SMTP(account["smtp_host"], account["smtp_port"])
                smtp.starttls()

            smtp.login(creds.email, creds.password)

            # All recipients
            all_recipients = list(request.to)
            if request.cc:
                all_recipients.extend(request.cc)
            if request.bcc:
                all_recipients.extend(request.bcc)

            smtp.sendmail(account["email"], all_recipients, msg.as_string())
            smtp.quit()

            return EmailSendResult(
                success=True,
                message_id=msg.get("Message-ID"),
            )

        except Exception as e:
            logger.error(f"Failed to send email: {e}")
            return EmailSendResult(success=False, error=str(e))
