#!/usr/bin/env python3
"""Standalone tests for backend/smtp_send.py — config parsing + send paths.

No network: smtplib.SMTP / SMTP_SSL are monkeypatched with a fake that records
the calls. Run directly or via backend/run_tests.py.
"""
import os
import smtplib

import smtp_send

FAILS = []


def check(cond, label):
    print(f"  {'ok' if cond else 'XX'}  {label}")
    if not cond:
        FAILS.append(label)


class FakeServer:
    def __init__(self, kind, log):
        self.kind, self.log = kind, log
        self.logged_in = None
        self.sent = []

    def ehlo(self, *a):
        self.log.append(("ehlo", self.kind))

    def starttls(self, *a, **k):
        self.log.append(("starttls", self.kind))

    def login(self, user, pw):
        self.logged_in = (user, pw)
        self.log.append(("login", user))

    def send_message(self, msg, from_addr=None, to_addrs=None):
        self.sent.append({"from_addr": from_addr, "to_addrs": to_addrs})
        self.log.append(("send", from_addr))

    def quit(self):
        self.log.append(("quit", self.kind))


def install_fakes():
    """Patch smtplib; return (log, holder) where holder['last'] is the server."""
    log, holder = [], {}

    def mk(kind):
        def factory(host, port, timeout=None, context=None):
            log.append((kind, host, port))
            srv = FakeServer(kind, log)
            holder["last"] = srv
            return srv
        return factory

    smtplib.SMTP = mk("SMTP")
    smtplib.SMTP_SSL = mk("SMTP_SSL")
    return log, holder


def set_env(**kw):
    for k in ("SMTP_HOST", "SMTP_PORT", "SMTP_FROM", "SMTP_USERNAME",
              "SMTP_PASSWORD", "SMTP_SECURITY"):
        os.environ.pop(k, None)
    for k, v in kw.items():
        os.environ["SMTP_" + k.upper()] = str(v)


def main():
    # 1. unconfigured
    set_env()
    check(not smtp_send.smtp_configured(), "smtp_configured() false when unset")
    try:
        smtp_send.load_smtp_config(); ok = False
    except smtp_send.SMTPNotConfigured:
        ok = True
    check(ok, "load_smtp_config raises SMTPNotConfigured without host")

    # 2. parse + normalize garbage
    set_env(host="smtp.x.com", port="nope", security="WEIRD", username="u@x", password="p")
    os.environ["SMTP_FROM"] = "f@x"
    cfg = smtp_send.load_smtp_config()
    check(cfg["host"] == "smtp.x.com", "host parsed")
    check(cfg["port"] == 587, "non-numeric port falls back to 587")
    check(cfg["security"] == "starttls", "unknown security falls back to starttls")

    # 3. STARTTLS path: plain SMTP, upgrade, auth, multi-recipient
    log, holder = install_fakes()
    set_env(host="h", port="587", security="starttls", username="u@x", password="pw")
    os.environ["SMTP_FROM"] = "f@x"
    res = smtp_send.send_email(["a@x.com", "b@x.com"], "s", "body")
    srv = holder["last"]
    check(log[0] == ("SMTP", "h", 587), "starttls connects via plain SMTP")
    check(("starttls", "SMTP") in log, "starttls negotiated")
    check(srv.logged_in == ("u@x", "pw"), "login with username/password")
    check(srv.sent[0]["from_addr"] == "f@x", "from = SMTP_FROM")
    check(srv.sent[0]["to_addrs"] == ["a@x.com", "b@x.com"], "recipients passed through")
    check(res["sent_to"] == ["a@x.com", "b@x.com"] and res["from"] == "f@x", "result reports send")

    # 4. implicit TLS path: SMTP_SSL, no STARTTLS
    log, holder = install_fakes()
    set_env(host="h", port="465", security="tls", username="u@x", password="pw")
    os.environ["SMTP_FROM"] = "f@x"
    smtp_send.send_email("a@x.com", "s", "b")
    check(log[0][0] == "SMTP_SSL", "tls uses SMTP_SSL")
    check(all(e[0] != "starttls" for e in log), "no STARTTLS on implicit TLS")

    # 5. security=none, from falls back to username
    log, holder = install_fakes()
    set_env(host="h", port="25", security="none", username="relay@x", password="")
    smtp_send.send_email("a@x.com", "s", "b")
    srv = holder["last"]
    check(all(e[0] != "starttls" for e in log), "no STARTTLS when security=none")
    check(srv.sent[0]["from_addr"] == "relay@x", "from falls back to username")

    # 6. no username -> no login attempted
    log, holder = install_fakes()
    set_env(host="h", port="25", security="none")
    os.environ["SMTP_FROM"] = "f@x"
    smtp_send.send_email("a@x.com", "s", "b")
    check(holder["last"].logged_in is None, "no login when username blank")

    # 7. no sender at all -> SMTPNotConfigured
    set_env(host="h", port="25", security="none")
    try:
        smtp_send.send_email("a@x.com", "s", "b"); ok = False
    except smtp_send.SMTPNotConfigured:
        ok = True
    check(ok, "no from/username raises SMTPNotConfigured")

    # 8. empty recipients -> ValueError
    set_env(host="h", port="587", security="starttls", username="u", password="p")
    os.environ["SMTP_FROM"] = "f@x"
    try:
        smtp_send.send_email([], "s", "b"); ok = False
    except ValueError:
        ok = True
    check(ok, "empty recipients raises ValueError")

    print()
    if FAILS:
        print(f"FAILED ({len(FAILS)}):")
        for f in FAILS:
            print(f"  - {f}")
        raise SystemExit(1)
    print("ALL PASS (smtp_send)")


if __name__ == "__main__":
    main()
