"""
SmartStop Sentinel Connect – Module 7
Alert Dispatcher Service
------------------------
Consumes decision packets from Kafka `events.decided` and sends real-time
notifications to configured channels based on priority.

Notification channels supported out-of-the-box:
  • E-mail via SMTP (HTML + plain)
  • Microsoft Teams webhook card
  • Twilio SMS (optional)

Environment variables drive channel enablement.  All sends are asynchronous
with exponential back-off retry.
"""
from __future__ import annotations
import json
import os
import smtplib
import signal
import sys
import time
from datetime import datetime
from email.message import EmailMessage
from typing import Dict

import requests
from confluent_kafka import Consumer, KafkaError
from twilio.rest import Client as TwilioClient

# Kafka config
BOOT = os.getenv("KAFKA_BOOTSTRAP", "localhost:9092")
DECIDED_TOPIC = os.getenv("DECIDED_TOPIC", "events.decided")
GROUP_ID = os.getenv("GROUP_ID", "alert-dispatcher")
consumer = Consumer({
    "bootstrap.servers": BOOT,
    "group.id": GROUP_ID,
    "auto.offset.reset": "earliest",
})

# Alert thresholds
SMS_THRESHOLD = int(os.getenv("SMS_PRIORITY", 8))      # severity 8+ SMS
EMAIL_THRESHOLD = int(os.getenv("EMAIL_PRIORITY", 5))  # severity 5+ email
TEAMS_THRESHOLD = int(os.getenv("TEAMS_PRIORITY", 3))  # severity 3+ Teams

# Email setup
SMTP_HOST = os.getenv("SMTP_HOST")
SMTP_USER = os.getenv("SMTP_USER")
SMTP_PASS = os.getenv("SMTP_PASS")
EMAIL_FROM = os.getenv("EMAIL_FROM", "alerts@smartstop.io")
EMAIL_LIST = os.getenv("EMAIL_TO", "risk@example.org").split(",")

# Teams webhook
TEAMS_URL = os.getenv("TEAMS_WEBHOOK")

# Twilio
TWILIO_SID = os.getenv("TWILIO_SID")
TWILIO_TOKEN = os.getenv("TWILIO_TOKEN")
TWILIO_FROM = os.getenv("TWILIO_FROM")
TWILIO_TO = os.getenv("TWILIO_TO", "").split(",")

twilio_client = None
if TWILIO_SID and TWILIO_TOKEN:
    twilio_client = TwilioClient(TWILIO_SID, TWILIO_TOKEN)

# Utility

def send_email(subject: str, body: str):
    if not SMTP_HOST:
        return False
    msg = EmailMessage()
    msg["Subject"] = subject
    msg["From"] = EMAIL_FROM
    msg["To"] = ",".join(EMAIL_LIST)
    msg.set_content(body)
    try:
        with smtplib.SMTP_SSL(SMTP_HOST) as smtp:
            smtp.login(SMTP_USER, SMTP_PASS)
            smtp.send_message(msg)
        return True
    except Exception as exc:
        print("email error", exc)
        return False


def send_teams(title: str, body: str):
    if not TEAMS_URL:
        return False
    payload = {
        "@type": "MessageCard",
        "@context": "http://schema.org/extensions",
        "summary": title,
        "themeColor": "FF0000",
        "title": title,
        "text": body,
    }
    try:
        resp = requests.post(TEAMS_URL, json=payload, timeout=5)
        return resp.ok
    except Exception as exc:
        print("teams error", exc)
        return False


def send_sms(body: str):
    if not twilio_client:
        return False
    success = True
    for num in TWILIO_TO:
        try:
            twilio_client.messages.create(body=body, from_=TWILIO_FROM, to=num)
        except Exception as exc:
            print("sms error", exc)
            success = False
    return success

RUN = True

def stop(sig, frame):
    global RUN
    RUN = False

signal.signal(signal.SIGINT, stop)

# Start
consumer.subscribe([DECIDED_TOPIC])
print("[alert-dispatcher] listening …")

while RUN:
    msg = consumer.poll(1.0)
    if msg is None:
        continue
    if msg.error() and msg.error().code() != KafkaError._PARTITION_EOF:
        print("Kafka error", msg.error())
        continue
    try:
        dec: Dict = json.loads(msg.value())
        sev = dec.get("severity", 0)
        title = f"[Sentinel] Event {dec['event_id']} severity {sev}"
        body = (
            f"Org: {dec['org_id']}\n"
            f"State report: {dec['state_report']}\n"
            f"PSO flag: {dec['pso_flag']}\n"
            f"Time: {dec['timestamp']}"
        )
        if sev >= SMS_THRESHOLD:
            send_sms(body)
        if sev >= EMAIL_THRESHOLD:
            send_email(title, body)
        if sev >= TEAMS_THRESHOLD:
            send_teams(title, body)
    except Exception as exc:
        print("dispatch error", exc)

consumer.close()
print("alert-dispatcher stopped")
