#!/usr/bin/env python3
"""
Genesis Slack Notification Bridge
===================================
Sends notifications to Slack channels.

PM-047: Slack Notification Bridge
- Sends to #genesis-alerts channel
- Supports message formatting
- Logs delivery status
"""

import os
import json
import logging
import requests
from typing import Dict, Any, List, Optional
from datetime import datetime
from dataclasses import dataclass, asdict

logger = logging.getLogger("SlackNotifier")
logging.basicConfig(level=logging.INFO)


@dataclass
class NotificationResult:
    """Result of notification delivery."""
    notification_id: str
    channel: str
    status: str
    timestamp: str
    message_preview: str
    error: Optional[str]

    def to_dict(self) -> Dict[str, Any]:
        return asdict(self)


class SlackNotifier:
    """
    Slack notification bridge for Genesis alerts.
    Sends formatted messages to configured Slack channels.
    """

    # Default channel mappings
    DEFAULT_CHANNELS = {
        "alerts": "#genesis-alerts",
        "revenue": "#genesis-revenue",
        "tasks": "#genesis-tasks",
        "errors": "#genesis-errors",
        "general": "#genesis"
    }

    # Alert severity colors
    SEVERITY_COLORS = {
        "info": "#36a64f",      # Green
        "warning": "#ff9800",   # Orange
        "error": "#f44336",     # Red
        "critical": "#9c27b0",  # Purple
        "success": "#4caf50"    # Light green
    }

    def __init__(self, webhook_url: str = None, bot_token: str = None):
        """
        Initialize Slack notifier.

        Args:
            webhook_url: Slack webhook URL for simple notifications
            bot_token: Slack Bot Token for rich API access
        """
        self.webhook_url = webhook_url or os.getenv("SLACK_WEBHOOK_URL")
        self.bot_token = bot_token or os.getenv("SLACK_BOT_TOKEN")
        self.api_base = "https://slack.com/api"

        # Notification log
        self.notification_log: List[NotificationResult] = []
        self.delivered_count = 0
        self.failed_count = 0

        logger.info(f"Slack Notifier initialized (webhook: {'Yes' if self.webhook_url else 'No'}, "
                   f"bot: {'Yes' if self.bot_token else 'No'})")

    def _generate_notification_id(self) -> str:
        """Generate unique notification ID."""
        import uuid
        return f"slk_{uuid.uuid4().hex[:12]}"

    def _get_channel(self, channel_type: str) -> str:
        """Get channel name from type."""
        return self.DEFAULT_CHANNELS.get(channel_type, channel_type)

    def send(self, message: str, channel: str = "alerts",
             severity: str = "info", title: str = None,
             fields: Dict[str, str] = None,
             mention_users: List[str] = None) -> NotificationResult:
        """
        Send notification to Slack.

        Args:
            message: Notification message
            channel: Channel type or name
            severity: Message severity (info, warning, error, critical, success)
            title: Optional title for rich message
            fields: Optional key-value fields
            mention_users: Optional list of user IDs to mention

        Returns:
            NotificationResult
        """
        notification_id = self._generate_notification_id()
        channel_name = self._get_channel(channel)

        # Build message
        payload = self._build_payload(
            message=message,
            channel=channel_name,
            severity=severity,
            title=title,
            fields=fields,
            mention_users=mention_users
        )

        # Send notification
        result = self._send_notification(payload, channel_name)

        # Create result record
        notification = NotificationResult(
            notification_id=notification_id,
            channel=channel_name,
            status=result.get("status", "unknown"),
            timestamp=datetime.utcnow().isoformat(),
            message_preview=message[:100],
            error=result.get("error")
        )

        # Update counters
        if notification.status == "delivered":
            self.delivered_count += 1
        else:
            self.failed_count += 1

        # Log
        self.notification_log.append(notification)
        logger.info(f"Slack notification [{notification_id}] to {channel_name}: {notification.status}")

        return notification

    def _build_payload(self, message: str, channel: str, severity: str,
                       title: str = None, fields: Dict[str, str] = None,
                       mention_users: List[str] = None) -> Dict[str, Any]:
        """Build Slack message payload."""
        color = self.SEVERITY_COLORS.get(severity, "#808080")

        # Build text with mentions
        text = message
        if mention_users:
            mentions = " ".join([f"<@{uid}>" for uid in mention_users])
            text = f"{mentions} {text}"

        # Simple webhook payload
        if self.webhook_url and not self.bot_token:
            payload = {
                "text": text,
                "attachments": [{
                    "color": color,
                    "title": title or "Genesis Notification",
                    "text": message,
                    "footer": "Genesis System",
                    "ts": int(datetime.utcnow().timestamp())
                }]
            }

            if fields:
                payload["attachments"][0]["fields"] = [
                    {"title": k, "value": v, "short": True}
                    for k, v in fields.items()
                ]

            return payload

        # Rich Bot API payload
        blocks = []

        # Header
        if title:
            blocks.append({
                "type": "header",
                "text": {"type": "plain_text", "text": title}
            })

        # Main message
        blocks.append({
            "type": "section",
            "text": {"type": "mrkdwn", "text": text}
        })

        # Fields
        if fields:
            field_elements = [
                {"type": "mrkdwn", "text": f"*{k}*\n{v}"}
                for k, v in fields.items()
            ]
            blocks.append({
                "type": "section",
                "fields": field_elements[:10]  # Max 10 fields
            })

        # Context footer
        blocks.append({
            "type": "context",
            "elements": [{
                "type": "mrkdwn",
                "text": f":robot_face: Genesis System | {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC"
            }]
        })

        return {
            "channel": channel,
            "blocks": blocks,
            "attachments": [{"color": color}]
        }

    def _send_notification(self, payload: Dict[str, Any],
                           channel: str) -> Dict[str, str]:
        """Send notification via webhook or API."""
        try:
            if self.webhook_url:
                response = requests.post(
                    self.webhook_url,
                    json=payload,
                    timeout=10
                )
                if response.status_code == 200:
                    return {"status": "delivered"}
                else:
                    return {"status": "failed", "error": response.text}

            elif self.bot_token:
                response = requests.post(
                    f"{self.api_base}/chat.postMessage",
                    headers={"Authorization": f"Bearer {self.bot_token}"},
                    json=payload,
                    timeout=10
                )
                data = response.json()
                if data.get("ok"):
                    return {"status": "delivered", "ts": data.get("ts")}
                else:
                    return {"status": "failed", "error": data.get("error")}

            else:
                return {"status": "skipped", "error": "No webhook or token configured"}

        except requests.exceptions.Timeout:
            return {"status": "failed", "error": "timeout"}
        except Exception as e:
            logger.error(f"Slack notification failed: {e}")
            return {"status": "failed", "error": str(e)}

    # ===== CONVENIENCE METHODS =====

    def send_alert(self, message: str, severity: str = "warning",
                   title: str = None) -> NotificationResult:
        """Send an alert notification."""
        return self.send(message, channel="alerts", severity=severity, title=title)

    def send_error(self, message: str, error_details: str = None,
                   component: str = None) -> NotificationResult:
        """Send an error notification."""
        fields = {}
        if error_details:
            fields["Error"] = error_details[:500]
        if component:
            fields["Component"] = component

        return self.send(
            message=message,
            channel="errors",
            severity="error",
            title="Error Alert",
            fields=fields
        )

    def send_revenue_update(self, amount: float, source: str,
                            details: str = None) -> NotificationResult:
        """Send revenue update notification."""
        fields = {
            "Amount": f"${amount:,.2f}",
            "Source": source
        }
        if details:
            fields["Details"] = details

        return self.send(
            message=f"New revenue recorded: ${amount:,.2f} from {source}",
            channel="revenue",
            severity="success",
            title="Revenue Update",
            fields=fields
        )

    def send_task_update(self, task_id: str, status: str,
                         description: str = None) -> NotificationResult:
        """Send task status update."""
        severity = "success" if status == "completed" else "info"
        if status == "failed":
            severity = "error"

        fields = {
            "Task ID": task_id,
            "Status": status
        }
        if description:
            fields["Description"] = description[:200]

        return self.send(
            message=f"Task {task_id} is now {status}",
            channel="tasks",
            severity=severity,
            title="Task Update",
            fields=fields
        )

    def send_system_status(self, status: str, components: Dict[str, str] = None,
                           message: str = None) -> NotificationResult:
        """Send system status notification."""
        severity = "success" if status == "healthy" else "warning"
        if status == "critical":
            severity = "critical"

        return self.send(
            message=message or f"System status: {status}",
            channel="alerts",
            severity=severity,
            title="System Status",
            fields=components
        )

    def get_notification_log(self, limit: int = 100,
                             status: str = None) -> List[Dict[str, Any]]:
        """Get notification log, optionally filtered by status."""
        logs = self.notification_log[-limit:]
        if status:
            logs = [n for n in logs if n.status == status]
        return [n.to_dict() for n in logs]

    def get_metrics(self) -> Dict[str, Any]:
        """Get notifier metrics."""
        return {
            "total_notifications": len(self.notification_log),
            "delivered": self.delivered_count,
            "failed": self.failed_count,
            "delivery_rate": round(
                self.delivered_count / max(1, len(self.notification_log)) * 100, 2
            ),
            "webhook_configured": bool(self.webhook_url),
            "bot_configured": bool(self.bot_token)
        }


# Global instance
_notifier: Optional[SlackNotifier] = None


def get_notifier() -> SlackNotifier:
    """Get or create global Slack notifier."""
    global _notifier
    if _notifier is None:
        _notifier = SlackNotifier()
    return _notifier


if __name__ == "__main__":
    # Self-test
    notifier = SlackNotifier()

    print("\n=== Slack Notifier Test ===")

    # Test alert
    result = notifier.send_alert("Test alert from Genesis", severity="info")
    print(f"Alert: {result.to_dict()}")

    # Test error
    result = notifier.send_error("Connection failed", "Timeout after 30s", "DatabaseConnector")
    print(f"Error: {result.to_dict()}")

    # Test revenue
    result = notifier.send_revenue_update(1250.00, "tradie_funnel", "New signup from Sydney")
    print(f"Revenue: {result.to_dict()}")

    # Test task
    result = notifier.send_task_update("task_123", "completed", "Processed 150 leads")
    print(f"Task: {result.to_dict()}")

    # Metrics
    print(f"\nMetrics: {notifier.get_metrics()}")
