"""
Transactional email dispatch.

In development (SMTP_HOST not configured) emails are logged to console.
In production set SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD / EMAIL_FROM.
"""
import asyncio
import logging
import re
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import parseaddr
from typing import Optional

from src.core.config import settings

logger = logging.getLogger(__name__)

_HEADER_UNSAFE_RE = re.compile(r"[\r\n\x00]")


def sanitize_header_value(value: Optional[str], default: str = "") -> str:
    """Strip CR/LF/NUL from a value before it is used in an email subject line.

    Prevents SMTP header injection (e.g. `\\r\\nBCC: attacker@evil.com`) when the
    value originates from user-submitted data such as a decedent or contact name.
    """
    if not value:
        return default
    cleaned = _HEADER_UNSAFE_RE.sub("", str(value)).strip()
    return cleaned or default


async def _dispatch(
    to: str,
    subject: str,
    body_text: str,
    body_html: str,
    cc: Optional[str] = None,
) -> None:
    """Send an email. In dev (no SMTP_HOST), logs to console."""
    if not settings.SMTP_HOST:
        logger.info("[EMAIL-DEV] To=%s | CC=%s | Subject=%s", to, cc, subject)
        return

    def _send_sync() -> None:
        msg = MIMEMultipart("alternative")
        msg["Subject"] = subject
        msg["From"] = settings.EMAIL_FROM
        msg["To"] = to
        if cc:
            msg["Cc"] = cc
        msg.attach(MIMEText(body_text, "plain", "utf-8"))
        msg.attach(MIMEText(body_html, "html", "utf-8"))
        recipients = [to] + ([cc] if cc else [])
        with smtplib.SMTP(settings.SMTP_HOST, settings.SMTP_PORT) as smtp:
            smtp.ehlo()
            smtp.starttls()
            smtp.ehlo()
            if settings.SMTP_USER:
                smtp.login(settings.SMTP_USER, settings.SMTP_PASSWORD)
            _, from_addr = parseaddr(settings.EMAIL_FROM)
            smtp.sendmail(from_addr or settings.EMAIL_FROM, recipients, msg.as_string())

    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, _send_sync)
