"""
Notification channels for the alerting system.
"""

import json
import smtplib
from abc import ABC, abstractmethod
from email.mime.text import MimeText
from email.mime.multipart import MimeMultipart
from typing import Dict, Any, Optional
import requests
import logging

logger = logging.getLogger(__name__)


class NotificationChannel(ABC):
    """Base class for notification channels."""

    @abstractmethod
    def send_alert(self, alert) -> bool:
        """
        Send an alert through this channel.

        Args:
            alert: Alert instance to send

        Returns:
            True if sent successfully, False otherwise
        """
        pass


class ConsoleChannel(NotificationChannel):
    """Console notification channel for development and testing."""

    def __init__(self, colored: bool = True):
        """
        Initialize console channel.

        Args:
            colored: Whether to use colored output
        """
        self.colored = colored
        self.colors = {
            'low': '\033[92m',      # Green
            'medium': '\033[93m',   # Yellow
            'high': '\033[91m',     # Red
            'critical': '\033[95m',  # Magenta
            'reset': '\033[0m'      # Reset
        }

    def send_alert(self, alert) -> bool:
        """Send alert to console."""
        try:
            severity_color = self.colors.get(
                alert.severity.value, '') if self.colored else ''
            reset_color = self.colors.get('reset', '') if self.colored else ''

            print(
                f"\n{severity_color}🚨 ALERT [{alert.severity.value.upper()}]{reset_color}")
            print(f"📋 Title: {alert.title}")
            print(f"⏰ Time: {alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
            print(f"💬 Message: {alert.message}")
            if alert.metadata:
                print(f"📊 Metadata: {json.dumps(alert.metadata, indent=2)}")
            print("-" * 50)

            return True
        except Exception as e:
            logger.error(f"Failed to send console alert: {str(e)}")
            return False


class EmailChannel(NotificationChannel):
    """Email notification channel."""

    def __init__(self, smtp_server: str, smtp_port: int, username: str,
                 password: str, from_email: str, to_emails: list,
                 use_tls: bool = True):
        """
        Initialize email channel.

        Args:
            smtp_server: SMTP server hostname
            smtp_port: SMTP server port
            username: SMTP username
            password: SMTP password
            from_email: From email address
            to_emails: List of recipient email addresses
            use_tls: Whether to use TLS encryption
        """
        self.smtp_server = smtp_server
        self.smtp_port = smtp_port
        self.username = username
        self.password = password
        self.from_email = from_email
        self.to_emails = to_emails
        self.use_tls = use_tls

    def send_alert(self, alert) -> bool:
        """Send alert via email."""
        try:
            # Create message
            msg = MimeMultipart()
            msg['From'] = self.from_email
            msg['To'] = ', '.join(self.to_emails)
            msg['Subject'] = f"[{alert.severity.value.upper()}] {alert.title}"

            # Create email body
            body = f"""
DataLineagePy Alert

Severity: {alert.severity.value.upper()}
Time: {alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')}
Alert ID: {alert.id}

Message:
{alert.message}

Metadata:
{json.dumps(alert.metadata, indent=2)}

---
This alert was generated by DataLineagePy
            """.strip()

            msg.attach(MimeText(body, 'plain'))

            # Send email
            server = smtplib.SMTP(self.smtp_server, self.smtp_port)
            if self.use_tls:
                server.starttls()
            server.login(self.username, self.password)
            server.send_message(msg)
            server.quit()

            logger.info(f"Email alert sent for {alert.id}")
            return True

        except Exception as e:
            logger.error(f"Failed to send email alert: {str(e)}")
            return False


class SlackChannel(NotificationChannel):
    """Slack notification channel."""

    def __init__(self, webhook_url: str, channel: Optional[str] = None,
                 username: str = "DataLineagePy"):
        """
        Initialize Slack channel.

        Args:
            webhook_url: Slack webhook URL
            channel: Slack channel (optional, can be set in webhook)
            username: Bot username
        """
        self.webhook_url = webhook_url
        self.channel = channel
        self.username = username
        self.emoji_map = {
            'low': ':green_circle:',
            'medium': ':yellow_circle:',
            'high': ':red_circle:',
            'critical': ':rotating_light:'
        }

    def send_alert(self, alert) -> bool:
        """Send alert to Slack."""
        try:
            emoji = self.emoji_map.get(alert.severity.value, ':warning:')

            # Create Slack message
            payload = {
                "username": self.username,
                "text": f"{emoji} *DataLineagePy Alert*",
                "attachments": [
                    {
                        "color": self._get_color(alert.severity.value),
                        "fields": [
                            {
                                "title": "Severity",
                                "value": alert.severity.value.upper(),
                                "short": True
                            },
                            {
                                "title": "Time",
                                "value": alert.timestamp.strftime('%Y-%m-%d %H:%M:%S'),
                                "short": True
                            },
                            {
                                "title": "Alert",
                                "value": alert.title,
                                "short": False
                            },
                            {
                                "title": "Message",
                                "value": alert.message,
                                "short": False
                            }
                        ],
                        "footer": f"Alert ID: {alert.id}"
                    }
                ]
            }

            if self.channel:
                payload["channel"] = self.channel

            # Send to Slack
            response = requests.post(
                self.webhook_url, json=payload, timeout=10)
            response.raise_for_status()

            logger.info(f"Slack alert sent for {alert.id}")
            return True

        except Exception as e:
            logger.error(f"Failed to send Slack alert: {str(e)}")
            return False

    def _get_color(self, severity: str) -> str:
        """Get color for alert severity."""
        color_map = {
            'low': 'good',
            'medium': 'warning',
            'high': 'danger',
            'critical': '#ff0000'
        }
        return color_map.get(severity, 'warning')


class WebhookChannel(NotificationChannel):
    """Generic webhook notification channel."""

    def __init__(self, webhook_url: str, headers: Optional[Dict[str, str]] = None,
                 timeout: int = 10):
        """
        Initialize webhook channel.

        Args:
            webhook_url: Webhook URL
            headers: Optional HTTP headers
            timeout: Request timeout in seconds
        """
        self.webhook_url = webhook_url
        self.headers = headers or {'Content-Type': 'application/json'}
        self.timeout = timeout

    def send_alert(self, alert) -> bool:
        """Send alert via webhook."""
        try:
            # Create webhook payload
            payload = {
                "alert_id": alert.id,
                "rule_id": alert.rule_id,
                "severity": alert.severity.value,
                "title": alert.title,
                "message": alert.message,
                "timestamp": alert.timestamp.isoformat(),
                "metadata": alert.metadata,
                "source": "DataLineagePy"
            }

            # Send webhook
            response = requests.post(
                self.webhook_url,
                json=payload,
                headers=self.headers,
                timeout=self.timeout
            )
            response.raise_for_status()

            logger.info(f"Webhook alert sent for {alert.id}")
            return True

        except Exception as e:
            logger.error(f"Failed to send webhook alert: {str(e)}")
            return False


class TeamsChannel(NotificationChannel):
    """Microsoft Teams notification channel."""

    def __init__(self, webhook_url: str):
        """
        Initialize Teams channel.

        Args:
            webhook_url: Teams webhook URL
        """
        self.webhook_url = webhook_url

    def send_alert(self, alert) -> bool:
        """Send alert to Microsoft Teams."""
        try:
            # Create Teams message card
            payload = {
                "@type": "MessageCard",
                "@context": "http://schema.org/extensions",
                "themeColor": self._get_theme_color(alert.severity.value),
                "summary": f"DataLineagePy Alert: {alert.title}",
                "sections": [
                    {
                        "activityTitle": f"🚨 DataLineagePy Alert",
                        "activitySubtitle": alert.title,
                        "facts": [
                            {
                                "name": "Severity",
                                "value": alert.severity.value.upper()
                            },
                            {
                                "name": "Time",
                                "value": alert.timestamp.strftime('%Y-%m-%d %H:%M:%S')
                            },
                            {
                                "name": "Alert ID",
                                "value": alert.id
                            }
                        ],
                        "text": alert.message
                    }
                ]
            }

            # Send to Teams
            response = requests.post(
                self.webhook_url, json=payload, timeout=10)
            response.raise_for_status()

            logger.info(f"Teams alert sent for {alert.id}")
            return True

        except Exception as e:
            logger.error(f"Failed to send Teams alert: {str(e)}")
            return False

    def _get_theme_color(self, severity: str) -> str:
        """Get theme color for alert severity."""
        color_map = {
            'low': '00FF00',      # Green
            'medium': 'FFFF00',   # Yellow
            'high': 'FF0000',     # Red
            'critical': 'FF00FF'  # Magenta
        }
        return color_map.get(severity, 'FFFF00')
