from __future__ import annotations

import smtplib
from datetime import datetime
from email.message import EmailMessage
from pathlib import Path
import re
import uuid

from app_core.paths import MAIL_OUTBOX_DIR


DEFAULT_MAIL_SETTINGS = {
    "delivery_mode": "smtp",
    "smtp_host": "",
    "smtp_port": 587,
    "smtp_username": "",
    "smtp_password": "",
    "smtp_use_tls": True,
    "mail_from": "",
    "reset_link_base_url": "",
    "local_outbox_dir": str(MAIL_OUTBOX_DIR),
}


def normalize_mail_settings(payload: dict | None) -> dict:
    normalized = dict(DEFAULT_MAIL_SETTINGS)
    if isinstance(payload, dict):
        for key in DEFAULT_MAIL_SETTINGS:
            if key in payload:
                normalized[key] = payload[key]
    try:
        normalized["smtp_port"] = int(normalized.get("smtp_port", 587) or 587)
    except Exception:
        normalized["smtp_port"] = 587
    delivery_mode = str(normalized.get("delivery_mode", "smtp") or "smtp").strip().lower()
    normalized["delivery_mode"] = delivery_mode if delivery_mode in {"smtp", "local"} else "smtp"
    normalized["smtp_use_tls"] = bool(normalized.get("smtp_use_tls", True))
    outbox_dir = str(normalized.get("local_outbox_dir", "")).strip()
    normalized["local_outbox_dir"] = outbox_dir or str(MAIL_OUTBOX_DIR)
    return normalized


def send_email(
    settings: dict,
    *,
    to_email: str,
    subject: str,
    body_text: str,
    body_html: str | None = None,
) -> str | None:
    mail_settings = normalize_mail_settings(settings)
    delivery_mode = str(mail_settings.get("delivery_mode", "smtp")).strip().lower()
    host = str(mail_settings.get("smtp_host", "")).strip()
    username = str(mail_settings.get("smtp_username", "")).strip()
    password = str(mail_settings.get("smtp_password", "")).strip()
    mail_from = str(mail_settings.get("mail_from", "")).strip() or username
    port = int(mail_settings.get("smtp_port", 587) or 587)
    use_tls = bool(mail_settings.get("smtp_use_tls", True))

    if not mail_from:
        raise ValueError("Mail From address is empty.")

    message = EmailMessage()
    message["From"] = mail_from
    message["To"] = str(to_email or "").strip()
    message["Subject"] = subject
    message.set_content(body_text)
    if str(body_html or "").strip():
        message.add_alternative(str(body_html), subtype="html")

    if delivery_mode == "local":
        outbox_dir = Path(str(mail_settings.get("local_outbox_dir", "")).strip() or MAIL_OUTBOX_DIR)
        outbox_dir.mkdir(parents=True, exist_ok=True)
        safe_email = re.sub(r"[^a-zA-Z0-9._-]+", "_", str(to_email or "").strip()) or "recipient"
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        file_path = outbox_dir / f"{timestamp}_{safe_email}_{uuid.uuid4().hex[:8]}.eml"
        file_path.write_text(message.as_string(), encoding="utf-8")
        return str(file_path)

    if not host:
        raise ValueError("SMTP host is empty.")

    with smtplib.SMTP(host, port, timeout=20) as smtp:
        smtp.ehlo()
        if use_tls:
            smtp.starttls()
            smtp.ehlo()
        if username:
            smtp.login(username, password)
        smtp.send_message(message)
    return None
