"""Alerting system with webhook, Telegram, and Discord channels.

Supports throttling, multiple channels, and structured alert payloads.
"""

from __future__ import annotations

import logging
import threading
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Protocol

import requests

logger = logging.getLogger("horizon.alerts")


class AlertType(str, Enum):
    FILL = "fill"
    RISK_TRIGGER = "risk_trigger"
    MARKET_RESOLUTION = "market_resolution"
    FEED_STALE = "feed_stale"
    ARB_WINDOW = "arb_window"
    PRICE_DEVIATION = "price_deviation"
    LIFECYCLE = "lifecycle"
    CUSTOM = "custom"


@dataclass
class Alert:
    """A single alert event."""
    alert_type: AlertType
    message: str
    timestamp: float = field(default_factory=time.time)
    data: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        return {
            "type": self.alert_type.value,
            "message": self.message,
            "timestamp": self.timestamp,
            "data": self.data,
        }


class AlertChannel(Protocol):
    """Protocol for alert delivery channels."""
    def send(self, alert: Alert) -> bool: ...


class WebhookChannel:
    """Send alerts via HTTP POST to a webhook URL."""

    def __init__(self, url: str, timeout: float = 5.0) -> None:
        self.url = url
        self.timeout = timeout

    def send(self, alert: Alert) -> bool:
        try:
            resp = requests.post(
                self.url,
                json=alert.to_dict(),
                timeout=self.timeout,
                headers={"Content-Type": "application/json"},
            )
            return resp.ok
        except Exception as e:
            logger.warning("Webhook alert failed: %s", e)
            return False


class TelegramChannel:
    """Send alerts to a Telegram chat via bot API."""

    def __init__(self, bot_token: str, chat_id: str) -> None:
        self.bot_token = bot_token
        self.chat_id = chat_id

    def send(self, alert: Alert) -> bool:
        url = f"https://api.telegram.org/bot{self.bot_token}/sendMessage"
        text = f"[{alert.alert_type.value.upper()}] {alert.message}"
        try:
            resp = requests.post(
                url,
                json={"chat_id": self.chat_id, "text": text, "parse_mode": "HTML"},
                timeout=5.0,
            )
            return resp.ok
        except Exception as e:
            logger.warning("Telegram alert failed: %s", e)
            return False


class DiscordChannel:
    """Send alerts to a Discord channel via webhook."""

    def __init__(self, webhook_url: str) -> None:
        self.webhook_url = webhook_url

    def send(self, alert: Alert) -> bool:
        payload = {
            "content": f"**[{alert.alert_type.value.upper()}]** {alert.message}",
        }
        try:
            resp = requests.post(
                self.webhook_url,
                json=payload,
                timeout=5.0,
            )
            return resp.ok
        except Exception as e:
            logger.warning("Discord alert failed: %s", e)
            return False


class LogChannel:
    """Send alerts to the Python logger (always available, no config needed)."""

    def send(self, alert: Alert) -> bool:
        logger.info("[%s] %s", alert.alert_type.value, alert.message)
        return True


class AlertManager:
    """Manages alert channels with throttling.

    Usage:
        mgr = AlertManager(channels=[WebhookChannel("https://...")])
        mgr.alert(AlertType.FILL, "Filled 10 @ 0.55", data={"market": "btc"})
    """

    def __init__(
        self,
        channels: list[Any] | None = None,
        max_alerts_per_window: int = 10,
        window_secs: float = 60.0,
    ) -> None:
        self.channels: list[Any] = channels or [LogChannel()]
        self.max_alerts_per_window = max_alerts_per_window
        self.window_secs = window_secs
        self._recent_timestamps: list[float] = []
        self._lock = threading.Lock()
        self._history: list[Alert] = []

    def alert(
        self,
        alert_type: AlertType,
        message: str,
        data: dict[str, Any] | None = None,
    ) -> bool:
        """Send an alert to all channels (with throttling).

        Returns True if the alert was sent, False if throttled.
        """
        if self._should_throttle():
            logger.debug("Alert throttled: %s", message)
            return False

        a = Alert(alert_type=alert_type, message=message, data=data or {})

        with self._lock:
            self._recent_timestamps.append(a.timestamp)
            self._history.append(a)
            # Cap history at 1000
            if len(self._history) > 1000:
                self._history = self._history[-500:]

        # Send to all channels (fire-and-forget in background threads)
        for channel in self.channels:
            threading.Thread(
                target=self._safe_send, args=(channel, a), daemon=True
            ).start()

        return True

    @staticmethod
    def _safe_send(channel: AlertChannel, alert: Alert) -> None:
        """Send an alert to a channel, catching exceptions."""
        try:
            channel.send(alert)
        except Exception as e:
            logger.warning("Alert channel failed: %s", e)

    def _should_throttle(self) -> bool:
        now = time.time()
        cutoff = now - self.window_secs
        with self._lock:
            self._recent_timestamps = [
                t for t in self._recent_timestamps if t > cutoff
            ]
            return len(self._recent_timestamps) >= self.max_alerts_per_window

    @property
    def recent_alerts(self) -> list[Alert]:
        """Get recent alert history."""
        return list(self._history[-50:])

    def clear_history(self) -> None:
        """Clear alert history."""
        with self._lock:
            self._history.clear()
            self._recent_timestamps.clear()
