"""SMTP service-layer unit tests.

Jinja-based HTTP flow tests (POST /config, POST /config/smtp/test via form) were
removed in M2-T11 when the Jinja routes were deleted.  HTTP-level SMTP test
endpoint coverage lives in test_api_config.py.
"""
import smtplib

from app.config import Settings
from app.services.email import (
    EmailDeliveryError,
    get_smtp_config,
    is_smtp_ready,
    send_public_ip_changed_email,
    send_smtp_test_email,
)


def _smtp_settings(**overrides) -> Settings:
    payload = {
        "app_env": "development",
        "app_hostname": "localhost:8000",
        "app_database_url": "sqlite:///./data/app.db",
        "auth_bootstrap_username": "admin",
        "auth_bootstrap_password": "secret-password",
        "smtp_enabled": True,
        "smtp_host": "smtp.example.com",
        "smtp_port": 587,
        "smtp_username": "smtp-user",
        "smtp_password": "super-secret-password",
        "smtp_from_name": "Home Automation",
        "smtp_from_address": "sender@example.com",
        "smtp_to_address": "recipient@example.com",
        "smtp_use_starttls": True,
    }
    payload.update(overrides)
    return Settings(_env_file=None, **payload)


def test_get_smtp_config_reads_runtime_values() -> None:
    settings = _smtp_settings(smtp_port=2525, smtp_use_starttls=False)

    smtp_config = get_smtp_config(settings)

    assert smtp_config.host == "smtp.example.com"
    assert smtp_config.port == 2525
    assert smtp_config.username == "smtp-user"
    assert smtp_config.password == "super-secret-password"
    assert smtp_config.from_name == "Home Automation"
    assert smtp_config.from_address == "sender@example.com"
    assert smtp_config.to_address == "recipient@example.com"
    assert smtp_config.use_starttls is False


def test_smtp_test_readiness_does_not_require_smtp_enabled() -> None:
    settings = _smtp_settings(smtp_enabled=False)

    assert is_smtp_ready(settings) is True


def test_send_smtp_test_email_success(monkeypatch) -> None:
    sent = {}

    class FakeSMTP:
        def __init__(self, host, port, timeout):
            sent["host"] = host
            sent["port"] = port
            sent["timeout"] = timeout

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc, tb):
            return None

        def ehlo(self):
            sent["ehlo"] = sent.get("ehlo", 0) + 1

        def starttls(self):
            sent["starttls"] = True

        def login(self, username, password):
            sent["username"] = username
            sent["password"] = password

        def send_message(self, message, from_addr=None, to_addrs=None):
            sent["subject"] = message["Subject"]
            sent["from"] = message["From"]
            sent["to"] = message["To"]
            sent["body"] = message.get_content()
            sent["envelope_from"] = from_addr
            sent["envelope_to"] = to_addrs

    monkeypatch.setattr("app.services.email.smtplib.SMTP", FakeSMTP)

    send_smtp_test_email(_smtp_settings())

    assert sent["host"] == "smtp.example.com"
    assert sent["port"] == 587
    assert sent["timeout"] == 10
    assert sent["starttls"] is True
    assert sent["username"] == "smtp-user"
    assert sent["password"] == "super-secret-password"
    assert sent["subject"] == "Home Automation SMTP Test"
    assert sent["from"] == "Home Automation <sender@example.com>"
    assert sent["to"] == "recipient@example.com"
    assert sent["envelope_from"] == "sender@example.com"
    assert sent["envelope_to"] == ["recipient@example.com"]
    assert "This is a test email" in sent["body"]


def test_send_smtp_test_email_does_not_require_smtp_enabled(monkeypatch) -> None:
    sent = {}

    class FakeSMTP:
        def __init__(self, host, port, timeout):
            sent["host"] = host

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc, tb):
            return None

        def ehlo(self):
            return None

        def starttls(self):
            return None

        def login(self, username, password):
            return None

        def send_message(self, message, from_addr=None, to_addrs=None):
            sent["subject"] = message["Subject"]
            sent["from"] = message["From"]
            sent["envelope_from"] = from_addr

    monkeypatch.setattr("app.services.email.smtplib.SMTP", FakeSMTP)

    send_smtp_test_email(_smtp_settings(smtp_enabled=False))

    assert sent["host"] == "smtp.example.com"
    assert sent["subject"] == "Home Automation SMTP Test"
    assert sent["from"] == "Home Automation <sender@example.com>"
    assert sent["envelope_from"] == "sender@example.com"


def test_send_smtp_test_email_failure_sanitizes_password(monkeypatch) -> None:
    class FakeSMTP:
        def __init__(self, host, port, timeout):
            pass

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc, tb):
            return None

        def ehlo(self):
            return None

        def starttls(self):
            raise smtplib.SMTPException("authentication failed for super-secret-password")

    monkeypatch.setattr("app.services.email.smtplib.SMTP", FakeSMTP)

    try:
        send_smtp_test_email(_smtp_settings())
        assert False, "expected EmailDeliveryError"
    except EmailDeliveryError as exc:
        assert "super-secret-password" not in str(exc)
        assert "[redacted]" in str(exc)


def test_send_public_ip_changed_email_contains_expected_english_content(monkeypatch) -> None:
    sent = {}

    class FakeSMTP:
        def __init__(self, host, port, timeout):
            sent["host"] = host

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc, tb):
            return None

        def ehlo(self):
            return None

        def starttls(self):
            return None

        def login(self, username, password):
            return None

        def send_message(self, message, from_addr=None, to_addrs=None):
            sent["subject"] = message["Subject"]
            sent["body"] = message.get_content()
            sent["from"] = message["From"]
            sent["envelope_from"] = from_addr

    monkeypatch.setattr("app.services.email.smtplib.SMTP", FakeSMTP)

    send_public_ip_changed_email(
        _smtp_settings(),
        previous_ipv4="203.0.113.10",
        current_ipv4="198.51.100.25",
        detected_at=__import__("datetime").datetime(2026, 4, 29, 10, 0, tzinfo=__import__("datetime").UTC),
    )

    assert sent["subject"] == "Public IP changed"
    assert sent["from"] == "Home Automation <sender@example.com>"
    assert sent["envelope_from"] == "sender@example.com"
    assert "Your public IPv4 address has changed." in sent["body"]
    assert "Previous IP: 203.0.113.10" in sent["body"]
    assert "Current IP: 198.51.100.25" in sent["body"]
    assert "Detected at: 2026-04-29 10:00:00 UTC" in sent["body"]
    assert "update the trusted IP manually" in sent["body"]
