"""Threshold-based alerting with command hooks and msmtp email support."""

from __future__ import annotations

import json
import shutil
import subprocess
import sys
from email.message import EmailMessage
from typing import Any

from sb_scout.models import AlertConfig


def check_alerts(
    rows: list[dict[str, Any]],
    alerts: AlertConfig,
) -> list[dict[str, Any]]:
    """Return rows that exceed any configured alert threshold."""
    if not _has_thresholds(alerts):
        return []

    hits: list[dict[str, Any]] = []
    for r in rows:
        if alerts.min_overall_score is not None and r.get("score_overall_rank", 0) >= alerts.min_overall_score:
            hits.append(r)
        elif alerts.min_cpu_score is not None and r.get("score_cpu_rank", 0) >= alerts.min_cpu_score:
            hits.append(r)
        elif alerts.min_storage_score is not None and r.get("score_storage_rank", 0) >= alerts.min_storage_score:
            hits.append(r)
        elif alerts.max_price is not None and r["price_amount"] <= alerts.max_price:
            hits.append(r)
    return hits


def build_alert_payload(hits: list[dict[str, Any]]) -> str:
    """Build the JSON alert payload."""
    return json.dumps({"alert_count": len(hits), "servers": hits}, indent=2)


def fire_notify(command: str, hits: list[dict[str, Any]]) -> None:
    """Run the notify command with alert context on stdin."""
    payload = build_alert_payload(hits)
    try:
        subprocess.run(
            command,
            shell=True,
            input=payload.encode(),
            timeout=30,
            check=False,
        )
    except subprocess.TimeoutExpired:
        print("Alert notify command timed out", file=sys.stderr)
    except OSError as e:
        print(f"Alert notify command failed: {e}", file=sys.stderr)


def send_msmtp_email(alerts: AlertConfig, hits: list[dict[str, Any]]) -> bool:
    """Send an alert email via local ``msmtp``.

    Returns True on best-effort success, False if msmtp is unavailable or the
    send failed.
    """
    recipients = tuple(alerts.email_to)
    if not recipients:
        return False

    msmtp_bin = shutil.which("msmtp")
    if not msmtp_bin:
        print("Alert email requested but msmtp is not installed", file=sys.stderr)
        return False

    msg = EmailMessage()
    msg["To"] = ", ".join(recipients)
    msg["Subject"] = alerts.email_subject or "sb-scout alert"
    if alerts.email_from:
        msg["From"] = alerts.email_from
    body = [
        f"sb-scout found {len(hits)} matching server(s).",
        "",
        build_alert_payload(hits),
    ]
    msg.set_content("\n".join(body))

    cmd = [msmtp_bin]
    if alerts.email_account:
        cmd.extend(["-a", alerts.email_account])
    cmd.extend(recipients)

    try:
        subprocess.run(
            cmd,
            input=msg.as_bytes(),
            timeout=30,
            check=False,
        )
        return True
    except subprocess.TimeoutExpired:
        print("Alert email via msmtp timed out", file=sys.stderr)
    except OSError as e:
        print(f"Alert email via msmtp failed: {e}", file=sys.stderr)
    return False


def _has_thresholds(alerts: AlertConfig) -> bool:
    return any([
        alerts.min_overall_score is not None,
        alerts.min_cpu_score is not None,
        alerts.min_storage_score is not None,
        alerts.max_price is not None,
    ])
