"""
Email service for sending transactional emails via SMTP.

Supports both sync (smtplib) and async (aiosmtplib) sending.
Configuration is resolved from settings JSON file, then env vars.
"""

import os
import logging
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from typing import Optional

logger = logging.getLogger(__name__)


def _get_smtp_config() -> dict:
    """Resolve SMTP config from admin settings file then env vars."""
    config = {}

    # Read from admin provider settings (same file as /admin/settings page)
    try:
        import json
        from pathlib import Path
        settings_path = Path("data/provider_settings.json")
        if settings_path.exists():
            with open(settings_path, "r") as f:
                settings = json.load(f)
            smtp = settings.get("smtp", {})
            if smtp and smtp.get("host"):
                config["host"] = smtp.get("host", "")
                config["port"] = smtp.get("port", 587)
                config["user"] = smtp.get("username", "")
                config["password"] = smtp.get("password", "")
                config["from_email"] = smtp.get("from_email", "") or smtp.get("username", "")
                config["use_tls"] = smtp.get("use_tls", True)
    except Exception:
        pass

    # Env vars fill gaps
    config.setdefault("host", os.getenv("SMTP_HOST", ""))
    config.setdefault("port", int(os.getenv("SMTP_PORT", "587")))
    config.setdefault("user", os.getenv("SMTP_USER", os.getenv("SMTP_USERNAME", "")))
    config.setdefault("password", os.getenv("SMTP_PASSWORD", ""))
    config.setdefault("from_email", os.getenv("SMTP_FROM_EMAIL", os.getenv("SMTP_USER", os.getenv("SMTP_USERNAME", ""))))
    config.setdefault("use_tls", os.getenv("SMTP_USE_TLS", "true").lower() == "true")

    return config


def is_smtp_configured() -> bool:
    """Check if SMTP is properly configured."""
    cfg = _get_smtp_config()
    return bool(cfg.get("host") and cfg.get("user"))


def send_email(to: str, subject: str, body: str) -> bool:
    """Send an email via SMTP (sync). Returns True if sent successfully."""
    cfg = _get_smtp_config()
    if not cfg.get("host"):
        logger.warning("SMTP not configured, email not sent")
        return False

    try:
        msg = MIMEMultipart("alternative")
        msg["Subject"] = subject
        msg["From"] = cfg["from_email"]
        msg["To"] = to
        msg.attach(MIMEText(body, "html"))

        port = int(cfg.get("port", 587))
        use_tls = cfg.get("use_tls", True)

        if use_tls:
            server = smtplib.SMTP(cfg["host"], port)
            server.starttls()
        else:
            server = smtplib.SMTP(cfg["host"], port)

        if cfg.get("user") and cfg.get("password"):
            server.login(cfg["user"], cfg["password"])

        server.sendmail(cfg["from_email"], [to], msg.as_string())
        server.quit()
        logger.info(f"Email sent to {to}: {subject}")
        return True
    except Exception as e:
        logger.error(f"Failed to send email to {to}: {e}")
        return False


async def send_email_async(to: str, subject: str, body: str) -> bool:
    """Send an email via SMTP (async). Returns True if sent successfully."""
    cfg = _get_smtp_config()
    if not cfg.get("host"):
        logger.warning("SMTP not configured, email not sent")
        return False

    try:
        from email.mime.text import MIMEText
        from email.mime.multipart import MIMEMultipart

        msg = MIMEMultipart("alternative")
        msg["Subject"] = subject
        msg["From"] = cfg["from_email"]
        msg["To"] = to
        msg.attach(MIMEText(body, "html"))

        port = int(cfg.get("port", 587))

        # Use sync smtplib inside a thread for reliability (aiosmtplib has quirks with raw messages)
        import asyncio
        return await asyncio.get_event_loop().run_in_executor(
            None, send_email, to, subject, body
        )
    except Exception as e:
        logger.error(f"Failed to send email (async) to {to}: {e}")
        return False
