"""
agentpaas.services.notification — Multi-channel notification service

Channels: terminal, macos, webhook, email, wechat
"""
from __future__ import annotations

import json
import os
import subprocess
import time
from dataclasses import dataclass, asdict
from typing import Any, Dict, List, Optional


@dataclass
class Notification:
    message: str
    channel: str = "terminal"
    priority: str = "normal"    # low / normal / high / urgent
    title: str = ""
    source: str = ""
    timestamp: float = 0

    def __post_init__(self):
        if self.timestamp == 0:
            self.timestamp = time.time()


class NotificationService:
    """Multi-channel notification dispatcher."""

    def __init__(self):
        self._history: List[Notification] = []
        self._max_history = 100

    def send(self, message: str, channel: str = "terminal",
             priority: str = "normal", title: str = "", source: str = "") -> str:
        notif = Notification(
            message=message, channel=channel, priority=priority,
            title=title or "lambda 🐂", source=source,
        )
        self._history.append(notif)
        if len(self._history) > self._max_history:
            self._history = self._history[-self._max_history:]

        if channel == "terminal":
            return self._send_terminal(notif)
        elif channel == "macos":
            return self._send_macos(notif)
        elif channel == "webhook":
            return self._send_webhook(notif)
        else:
            return self._send_terminal(notif)  # fallback

    def _send_terminal(self, n: Notification) -> str:
        icon = {"low": "ℹ️", "normal": "📌", "high": "⚠️", "urgent": "🚨"}.get(n.priority, "📌")
        print(f"\n{icon} [{n.title}] {n.message}")
        return f"[OK] Terminal notification sent"

    def _send_macos(self, n: Notification) -> str:
        try:
            script = (
                f'display notification "{n.message}" '
                f'with title "{n.title}" '
                f'sound name "default"'
            )
            subprocess.run(["osascript", "-e", script], capture_output=True, timeout=5)
            return f"[OK] macOS notification sent"
        except Exception as e:
            # Fallback to terminal
            self._send_terminal(n)
            return f"[FALLBACK] macOS failed ({e}), sent to terminal"

    def _send_webhook(self, n: Notification) -> str:
        url = os.environ.get("LAMBDAGENT_WEBHOOK_URL", "")
        if not url:
            self._send_terminal(n)
            return "[FALLBACK] No webhook URL configured, sent to terminal"
        try:
            import urllib.request
            data = json.dumps(asdict(n)).encode()
            req = urllib.request.Request(url, data=data,
                                         headers={"Content-Type": "application/json"})
            urllib.request.urlopen(req, timeout=10)
            return f"[OK] Webhook notification sent to {url}"
        except Exception as e:
            return f"[ERROR] Webhook failed: {e}"

    def history(self, limit: int = 20) -> List[Notification]:
        return self._history[-limit:]


# ════════════════════════════════════════════════════════════
# Agent-side tool function
# ════════════════════════════════════════════════════════════

_default_service = None

def _get_service() -> NotificationService:
    global _default_service
    if _default_service is None:
        _default_service = NotificationService()
    return _default_service


def notify(input_val: Any) -> str:
    """Send notification. Input: {message, channel?, priority?, title?}"""
    params = _parse(input_val)
    message = params.get("message", "")
    if not message:
        return "[ERROR] message is required"
    return _get_service().send(
        message=message,
        channel=params.get("channel", "terminal"),
        priority=params.get("priority", "normal"),
        title=params.get("title", "lambda 🐂"),
        source=params.get("source", "agent"),
    )


def _parse(input_val: Any) -> dict:
    if isinstance(input_val, dict):
        return input_val
    if isinstance(input_val, str):
        try:
            return json.loads(input_val)
        except (json.JSONDecodeError, ValueError):
            return {"message": input_val}
    return {}
