"""
alert_service.py — alertes opérationnelles par e-mail à l'équipe (ALERT_EMAIL).

À utiliser pour tout ce qui exige une intervention humaine : webhook Stripe en
échec, organizer bloqué, suppression RGPD massive, backup en échec, erreur 500.

- Anti-spam : une même clé (`key`) ne déclenche qu'un e-mail par ALERT_COOLDOWN_SECS
  (conservé en base, donc partagé entre workers et redémarrages).
- Toujours journalisé (ERROR) même sans SMTP ; ne lève jamais d'exception.
"""
import logging
import os
import smtplib
import threading
import time
from email.mime.text import MIMEText

from core import config
from core.db import get_db, named_lock

log = logging.getLogger("meeconic.alert")


def _cooldown_ok(key: str) -> bool:
    now = time.time()
    try:
        with named_lock(f"alert:{key}"), get_db() as conn:
            row = conn.execute("SELECT value FROM app_kv WHERE key=?", (f"alert:{key}",)).fetchone()
            if row and now - float(row["value"]) < config.ALERT_COOLDOWN_SECS:
                return False
            conn.execute("INSERT OR REPLACE INTO app_kv (key, value) VALUES (?,?)", (f"alert:{key}", str(now)))
            conn.commit()
        return True
    except Exception:
        return True  # en cas de doute, mieux vaut alerter deux fois que jamais


def _smtp_send(subject: str, body: str) -> None:
    host = os.getenv("SMTP_HOST", "smtp-relay.brevo.com")
    port = int(os.getenv("SMTP_PORT", "587"))
    user = os.getenv("SMTP_USER", "").strip()
    pw = os.getenv("SMTP_PASSWORD", os.getenv("SMTP_PASS", "")).replace(" ", "")
    sender = os.getenv("SMTP_FROM", user).strip()
    if not (user and pw and config.ALERT_EMAIL):
        return
    msg = MIMEText(body, "plain", "utf-8")
    msg["Subject"] = f"[Meeconic ALERTE] {subject}"
    msg["From"] = sender
    msg["To"] = config.ALERT_EMAIL
    try:
        with smtplib.SMTP(host, port, timeout=20) as s:
            s.starttls()
            s.login(user, pw)
            s.send_message(msg)
        log.info("Alert sent to %s: %s", config.ALERT_EMAIL, subject)
    except Exception as e:
        log.error("Envoi de l'alerte impossible (%s): %s", subject, e)


def notify(key: str, subject: str, body: str = "") -> None:
    """Journalise (ERROR) et envoie un e-mail d'alerte (avec anti-spam par clé)."""
    try:
        log.error("ALERTE [%s] %s — %s", key, subject, body)
        if config.APP_ENV == "test" or not config.ALERT_EMAIL:
            return
        if not _cooldown_ok(key):
            return
        threading.Thread(target=_smtp_send, args=(subject, f"{subject}\n\n{body}\n\nEnv: {config.APP_ENV}"),
                         daemon=True).start()
    except Exception as e:  # une alerte ne doit jamais casser l'appelant
        log.error("alert_service.notify failed: %s", e)
