"""Outbound email for auth (password reset). Configure SMTP or AUTH_MAIL_LOG_ONLY for dev."""

from __future__ import annotations

import asyncio
import logging
import os
import smtplib
import ssl
from email.message import EmailMessage
from typing import Literal

logger = logging.getLogger(__name__)

OtpDeliveryChannel = Literal["smtp", "log_only", "none"]


def public_web_origin() -> str:
    raw = (os.getenv("AUTH_PUBLIC_WEB_ORIGIN") or os.getenv("PUBLIC_WEB_ORIGIN") or "").strip()
    if raw:
        return raw.rstrip("/")
    return "http://localhost:8081"


def reset_link(raw_token: str) -> str:
    base = public_web_origin()
    return f"{base}/reset-password?token={raw_token}"


def verify_email_link(raw_token: str) -> str:
    base = public_web_origin()
    return f"{base}/verify-email?token={raw_token}"


def _registration_otp_validity_phrase_vi() -> str:
    """Mirror auth_api REGISTER_OTP_TTL_MINUTES default for email copy."""
    raw = os.getenv("REGISTER_OTP_TTL_MINUTES", "1").strip()
    try:
        minutes = int(raw or "1")
    except ValueError:
        minutes = 1
    minutes = max(1, min(minutes, 24 * 60))
    if minutes == 1:
        return "1 phút"
    return f"{minutes} phút"




def mail_delivery_configured() -> bool:
    if os.getenv("AUTH_MAIL_LOG_ONLY", "").lower() in ("1", "true", "yes"):
        return True
    return bool(os.getenv("SMTP_HOST", "").strip())


def _send_smtp_sync(to_email: str, subject: str, text_body: str, html_body: str) -> None:
    host = os.getenv("SMTP_HOST", "").strip()
    port = int(os.getenv("SMTP_PORT", "587"))
    user = os.getenv("SMTP_USER", "").strip()
    password = os.getenv("SMTP_PASSWORD", "").strip()
    mail_from = os.getenv("AUTH_MAIL_FROM", user or "noreply@localhost").strip()

    if user and not password:
        logger.warning(
            "SMTP_USER is set but SMTP_PASSWORD is empty; login will fail (535). "
            "With Docker Compose from the repo root, define SMTP_* in the root `.env` "
            "so interpolation passes them into the be0 service (be0/.env is not loaded unless env_file is set)."
        )

    msg = EmailMessage()
    msg["Subject"] = subject
    msg["From"] = mail_from
    msg["To"] = to_email
    msg.set_content(text_body)
    msg.add_alternative(html_body, subtype="html")

    context = ssl.create_default_context()
    with smtplib.SMTP(host, port, timeout=30) as server:
        if os.getenv("SMTP_USE_TLS", "1").lower() in ("1", "true", "yes"):
            server.starttls(context=context)
        if user:
            try:
                server.login(user, password)
            except smtplib.SMTPAuthenticationError as e:
                logger.warning(
                    "SMTP login failed for user %s (code %s): %s. "
                    "If using Microsoft 365 / Outlook, use the mailbox full email as SMTP_USER, "
                    "set SMTP_PASSWORD to an app password when MFA is on, and ensure "
                    "Authenticated SMTP (SMTP AUTH) is enabled for that mailbox in the tenant.",
                    user,
                    e.smtp_code,
                    e.smtp_error.decode(errors="replace") if isinstance(e.smtp_error, bytes) else e.smtp_error,
                )
                raise
        server.send_message(msg)


async def deliver_password_reset_email(to_email: str, raw_token: str) -> None:
    """Log link, send via SMTP, or no-op with warning if misconfigured."""
    link = reset_link(raw_token)
    if os.getenv("AUTH_MAIL_LOG_ONLY", "").lower() in ("1", "true", "yes"):
        logger.info("AUTH_MAIL_LOG_ONLY: password reset link for %s: %s", to_email, link)
        return

    host = os.getenv("SMTP_HOST", "").strip()
    if not host:
        logger.warning(
            "Password reset token created but mail is not configured "
            "(set SMTP_HOST or AUTH_MAIL_LOG_ONLY=1). User: %s",
            to_email,
        )
        return

    subject = "Đặt lại mật khẩu — hệ thống sáng kiến"
    text_body = (
        "Bạn (hoặc ai đó) đã yêu cầu đặt lại mật khẩu.\n\n"
        f"Mở liên kết sau (hiệu lực giới hạn):\n{link}\n\n"
        "Nếu bạn không yêu cầu, hãy bỏ qua email này."
    )
    html_body = (
        "<p>Bạn (hoặc ai đó) đã yêu cầu đặt lại mật khẩu.</p>"
        f'<p><a href="{link}">Đặt lại mật khẩu</a></p>'
        "<p>Nếu bạn không yêu cầu, hãy bỏ qua email này.</p>"
    )
    await asyncio.to_thread(_send_smtp_sync, to_email, subject, text_body, html_body)


async def deliver_registration_otp_email(to_email: str, otp_plaintext: str) -> OtpDeliveryChannel:
    """Send OTP via SMTP, log plaintext when AUTH_MAIL_LOG_ONLY=1, or no-op when SMTP unset."""
    ttl_phrase = _registration_otp_validity_phrase_vi()
    if os.getenv("AUTH_MAIL_LOG_ONLY", "").lower() in ("1", "true", "yes"):
        logger.info("AUTH_MAIL_LOG_ONLY: registration OTP for %s: %s", to_email, otp_plaintext)
        return "log_only"

    host = os.getenv("SMTP_HOST", "").strip()
    if not host:
        logger.warning(
            "Registration OTP created but mail is not configured "
            "(set SMTP_HOST or AUTH_MAIL_LOG_ONLY=1). User: %s",
            to_email,
        )
        return "none"

    subject = "Mã xác minh đăng ký — hệ thống sáng kiến"
    text_body = (
        "Cảm ơn bạn đã đăng ký.\n\n"
        f"Mã xác minh của bạn: {otp_plaintext}\n\n"
        f"Mã có hiệu lực trong {ttl_phrase}. Nhập đúng 6 chữ số trên trang đăng ký "
        "ngay sau khi nhận email.\n"
        "Nếu bạn không đăng ký, hãy bỏ qua email này."
    )
    html_body = (
        "<p>Cảm ơn bạn đã đăng ký.</p>"
        f"<p>Mã xác minh (nhập trên trang đăng ký): <strong>{otp_plaintext}</strong></p>"
        f"<p>Mã có hiệu lực trong <strong>{ttl_phrase}</strong>; vui lòng nhập mã trong thời gian này.</p>"
        "<p>Nếu bạn không đăng ký, hãy bỏ qua email này.</p>"
    )
    await asyncio.to_thread(_send_smtp_sync, to_email, subject, text_body, html_body)
    return "smtp"


async def deliver_email_verification_email(to_email: str, raw_token: str) -> None:
    """Log link, send via SMTP, or warn if misconfigured (same policy as password reset)."""
    link = verify_email_link(raw_token)
    if os.getenv("AUTH_MAIL_LOG_ONLY", "").lower() in ("1", "true", "yes"):
        logger.info("AUTH_MAIL_LOG_ONLY: verify-email link for %s: %s", to_email, link)
        return

    host = os.getenv("SMTP_HOST", "").strip()
    if not host:
        logger.warning(
            "Email verification token created but mail is not configured "
            "(set SMTP_HOST or AUTH_MAIL_LOG_ONLY=1). User: %s",
            to_email,
        )
        return

    subject = "Xác minh email — hệ thống sáng kiến"
    text_body = (
        "Cảm ơn bạn đã đăng ký.\n\n"
        f"Mở liên kết sau để kích hoạt tài khoản (hiệu lực giới hạn):\n{link}\n\n"
        "Nếu bạn không đăng ký, hãy bỏ qua email này."
    )
    html_body = (
        "<p>Cảm ơn bạn đã đăng ký.</p>"
        f'<p><a href="{link}">Xác minh email và kích hoạt tài khoản</a></p>'
        "<p>Nếu bạn không đăng ký, hãy bỏ qua email này.</p>"
    )
    await asyncio.to_thread(_send_smtp_sync, to_email, subject, text_body, html_body)
