"""E-Mail-Versand: Rechnung an Mitglied, SEPA-XMLs an Admin."""

import email.utils
import glob as _glob
import json
import logging
import os
import smtplib
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from core.models import Mitglied, SEX_MALE, SEX_FEMALE

logger = logging.getLogger(__name__)


def _resolve_smtp(system) -> dict:
    """Löst SMTP-Zugangsdaten auf (Priorität: Config → smtp_config.json → Env-Vars).

    Gibt ein Dict mit Keys: mode, server, port, user, password, from_address.
    """
    _session_server = str(system.config.get("SMTP_Server", "") or "").strip()
    _session_mode   = str(system.config.get("SMTP_Mode",   "") or "").strip().lower()
    _session_user   = str(system.config.get("SMTP_User",   "") or "").strip()
    _session_pass   = str(system.config.get("SMTP_Pass",   "") or "")

    if _session_server and _session_user:
        mode = _session_mode or "starttls"
        return {
            "mode":         mode,
            "server":       _session_server,
            "port":         587 if mode == "starttls" else 465,
            "user":         _session_user,
            "password":     _session_pass,
            "from_address": _session_user,
        }

    # Priorität 2+3: smtp_config.json und Env-Vars
    _smtp_cfg_path = os.path.join(os.path.dirname(__file__), "..", "smtp_config.json")
    _smtp_file: dict = {}
    if os.path.exists(_smtp_cfg_path):
        try:
            _smtp_file = json.loads(open(_smtp_cfg_path, encoding="utf-8").read())
        except Exception:
            pass

    mode      = (_smtp_file.get("mode")     or os.environ.get("EEG_SMTP_MODE", "ssl")).strip().lower()
    server    = (_smtp_file.get("server")   or os.environ.get("EEG_SMTP_SERVER", "")).strip()
    _port_raw = _smtp_file.get("port")      or os.environ.get("EEG_SMTP_PORT", "")
    port      = int(_port_raw) if _port_raw else (465 if mode == "ssl" else 587)
    user      = (_smtp_file.get("username") or os.environ.get("EEG_SMTP_USERNAME", "")).strip()
    password  = _smtp_file.get("password")  or os.environ.get("EEG_SMTP_PASSWORD", "")
    from_addr = (_smtp_file.get("from_address") or os.environ.get("EEG_SMTP_FROM", "") or user).strip()

    return {
        "mode": mode, "server": server, "port": port,
        "user": user, "password": password, "from_address": from_addr,
    }


def _smtp_send(smtp: dict, msg) -> None:
    """Stellt die SMTP-Verbindung her und sendet die Nachricht."""
    if not smtp["server"] or not smtp["user"]:
        raise ValueError("SMTP-Konfiguration unvollständig (Server oder Benutzername fehlt).")

    if smtp["mode"] == "starttls":
        with smtplib.SMTP(smtp["server"], smtp["port"], timeout=10) as server:
            server.ehlo()
            server.starttls()
            server.ehlo()
            server.login(smtp["user"], smtp["password"])
            server.send_message(msg)
    else:
        with smtplib.SMTP_SSL(smtp["server"], smtp["port"], timeout=10) as server:
            server.login(smtp["user"], smtp["password"])
            server.send_message(msg)


def send_email(system, mitglied: Mitglied, test_email: str = None) -> None:
    """Versendet die Rechnung (PDF) per E-Mail an das Mitglied.

    test_email: falls angegeben, wird die Mail an diese Adresse gesendet (Test-Modus).
    """
    smtp = _resolve_smtp(system)
    vereinsname = str(system.config.get("Vereinsname", "EEG"))
    reply_to    = system.config.get("Mail_ReplyTo", "").strip() or None

    msg = MIMEMultipart()
    msg["From"]       = email.utils.formataddr((vereinsname, smtp["from_address"]))
    recipient         = test_email if test_email else mitglied.Mail
    msg["To"]         = recipient
    if reply_to:
        msg["Reply-To"] = reply_to
    msg["Message-ID"] = email.utils.make_msgid()
    msg["Date"]       = email.utils.formatdate()

    # E-Mail-Vorlage aus JSON laden (Fallback: hardcoded)
    vorlage_path = os.path.join(system.main_path, "Config", "email_vorlage.json")
    try:
        with open(vorlage_path, encoding="utf-8") as vf:
            vorlage = json.load(vf)
    except Exception:
        vorlage = {
            "betreff":        "Rechnung {Periode} – {Vereinsname}",
            "anrede_m":       "Lieber",
            "anrede_w":       "Liebe",
            "anrede_default": "Liebe/r",
            "body": (
                "{Anrede} {Name},\n\nim Anhang befindet sich Ihre Rechnung von {Vereinsname}.\n"
                "Der Betrag von {Betrag} € wird am {Datum} {Aktion}.\n\n"
                "Freundliche Grüße,\n{Vereinsname}"
            ),
        }

    anrede = (
        vorlage.get("anrede_m", "Lieber")       if mitglied.Sex == SEX_MALE
        else vorlage.get("anrede_w", "Liebe")   if mitglied.Sex == SEX_FEMALE
        else vorlage.get("anrede_default", "Liebe/r")
    )
    aktion = "abgebucht" if mitglied.Kosten > 0 else "gutgeschrieben"

    replacements = {
        "{Anrede}":     anrede,
        "{Name}":       mitglied.Name,
        "{Vereinsname}": str(system.config.get("Vereinsname", "")),
        "{Periode}":    str(system.periode),
        "{Betrag}":     f"{abs(mitglied.Kosten):.2f}".replace(".", ","),
        "{Datum}":      system.datum_abbuchung.strftime("%d.%m.%Y"),
        "{Aktion}":     aktion,
    }

    betreff_tmpl = vorlage.get("betreff", system.config.get("MAIL_Betreff", "Rechnung"))
    body_tmpl    = vorlage.get("body", "")
    for k, v in replacements.items():
        betreff_tmpl = betreff_tmpl.replace(k, v)
        body_tmpl    = body_tmpl.replace(k, v)

    betreff = betreff_tmpl
    if test_email:
        betreff = f"[TEST] {betreff} – {mitglied.Name}"
    msg["Subject"] = betreff

    body = body_tmpl
    if test_email:
        body += f"\n\n(TEST – ursprüngliche Empfänger: {mitglied.Mail})"
    msg.attach(MIMEText(body, "plain"))

    pdf_path = os.path.join(
        system.folder_rechnungen,
        f"Rechnung_{mitglied.Rechnungsnummer}_{mitglied.Name4Rechnung}.pdf",
    )
    with open(pdf_path, "rb") as f:
        attachment = MIMEApplication(f.read(), _subtype="pdf")
        attachment.add_header("Content-Disposition", "attachment",
                              filename=os.path.basename(pdf_path))
        msg.attach(attachment)

    try:
        _smtp_send(smtp, msg)
    except (smtplib.SMTPException, OSError) as e:
        logger.error(f"SMTP-Fehler beim Senden an {msg['To']}: {e}")
        raise
    logger.info(f'E-Mail an {msg["To"]} gesendet.')


def send_sepa_email(system, to_addr: str, periode: str = "") -> None:
    """Sendet alle SEPA-XML-Dateien aus folder_sepa als Anhänge an to_addr."""
    smtp = _resolve_smtp(system)

    xml_files = sorted(_glob.glob(os.path.join(system.folder_sepa, "*.xml")))
    if not xml_files:
        logger.warning("send_sepa_email: Keine XML-Dateien in folder_sepa gefunden.")
        return

    vereinsname = str(system.config.get("Vereinsname", "EEG"))
    periode_str = periode or str(system.config.get("Periode", ""))

    msg = MIMEMultipart()
    msg["From"]       = email.utils.formataddr((vereinsname, smtp["from_address"]))
    msg["To"]         = to_addr
    msg["Message-ID"] = email.utils.make_msgid()
    msg["Date"]       = email.utils.formatdate()
    msg["Subject"]    = f"SEPA-Dateien {vereinsname} – {periode_str}".strip(" –")

    body = (
        f"Sehr geehrte Damen und Herren,\n\n"
        f"anbei die SEPA-Dateien für den Abrechnungszeitraum {periode_str} "
        f"von {vereinsname}.\n\n"
        f"Mit freundlichen Grüßen\n{vereinsname}"
    )
    msg.attach(MIMEText(body, "plain"))

    for xml_path in xml_files:
        with open(xml_path, "rb") as f:
            att = MIMEApplication(f.read(), _subtype="xml")
            att.add_header("Content-Disposition", "attachment",
                           filename=os.path.basename(xml_path))
            msg.attach(att)

    try:
        _smtp_send(smtp, msg)
    except (smtplib.SMTPException, OSError) as e:
        logger.error(f"SMTP-Fehler beim SEPA-Versand an {to_addr}: {e}")
        raise
    logger.info(f"SEPA-E-Mail mit {len(xml_files)} Anhängen an {to_addr} gesendet.")
