"""
Notification system for cronjob events.
"""

import logging
from typing import List, Optional
from django.conf import settings
from django.core.mail import send_mail
from django_cronjob_utils.models import CronExecution

# Import requests at module level for testability
try:
    import requests
except ImportError:
    requests = None

logger = logging.getLogger(__name__)


class NotificationBackend:
    """Base class for notification backends."""
    
    def notify_failure(self, execution: CronExecution, error_message: str):
        """Send failure notification."""
        raise NotImplementedError
    
    def notify_success(self, execution: CronExecution, message: str = ''):
        """Send success notification (optional)."""
        pass


class EmailBackend(NotificationBackend):
    """Email notification backend."""
    
    def __init__(self, config: dict):
        self.recipients = config.get('recipients', [])
        self.from_email = config.get('from_email', settings.DEFAULT_FROM_EMAIL)
        self.subject_template = config.get('subject_template', 'Cronjob Failed: {task_name}')
    
    def notify_failure(self, execution: CronExecution, error_message: str):
        """Send failure notification via email."""
        if not self.recipients:
            logger.warning("Email backend configured but no recipients specified")
            return
        
        subject = self.subject_template.format(
            task_name=execution.task_name,
            task_code=execution.task_code
        )
        
        message = f"""
Cronjob Execution Failed

Task: {execution.task_name} ({execution.task_code})
Execution Date: {execution.execution_date}
Started: {execution.started}
Error Code: {execution.error_code or 'N/A'}

Error Message:
{error_message}

Message:
{execution.message or 'N/A'}

Please check the execution logs for more details.
"""
        
        try:
            send_mail(
                subject=subject,
                message=message,
                from_email=self.from_email,
                recipient_list=self.recipients,
                fail_silently=False,
            )
            logger.info(f"Email notification sent for failed task {execution.task_name}")
        except Exception as e:
            logger.error(f"Failed to send email notification: {e}")


class SlackBackend(NotificationBackend):
    """Slack notification backend."""
    
    def __init__(self, config: dict):
        self.webhook_url = config.get('webhook_url')
        self.channel = config.get('channel', '#cronjobs')
        self.username = config.get('username', 'Cronbot')
        
        if not self.webhook_url:
            raise ValueError("Slack webhook_url is required")
    
    def notify_failure(self, execution: CronExecution, error_message: str):
        """Send failure notification via Slack."""
        if requests is None:
            logger.error("requests library is required for Slack notifications. Install it with: pip install requests")
            return
        
        payload = {
            'channel': self.channel,
            'username': self.username,
            'text': f'❌ Cronjob Failed: {execution.task_name}',
            'attachments': [
                {
                    'color': 'danger',
                    'fields': [
                        {'title': 'Task', 'value': f'{execution.task_name} ({execution.task_code})', 'short': True},
                        {'title': 'Date', 'value': str(execution.execution_date), 'short': True},
                        {'title': 'Started', 'value': execution.started.strftime('%Y-%m-%d %H:%M:%S'), 'short': True},
                        {'title': 'Error Code', 'value': execution.error_code or 'N/A', 'short': True},
                        {'title': 'Error Message', 'value': error_message[:500], 'short': False},
                    ]
                }
            ]
        }
        
        try:
            response = requests.post(self.webhook_url, json=payload, timeout=10)
            response.raise_for_status()
            logger.info(f"Slack notification sent for failed task {execution.task_name}")
        except Exception as e:
            logger.error(f"Failed to send Slack notification: {e}")


class TelegramBackend(NotificationBackend):
    """Telegram notification backend."""
    
    def __init__(self, config: dict):
        self.bot_token = config.get('bot_token')
        self.chat_id = config.get('chat_id')
        
        if not self.bot_token:
            raise ValueError("Telegram bot_token is required")
        if not self.chat_id:
            raise ValueError("Telegram chat_id is required")
        
        self.api_url = f"https://api.telegram.org/bot{self.bot_token}/sendMessage"
    
    def notify_failure(self, execution: CronExecution, error_message: str):
        """Send failure notification via Telegram."""
        if requests is None:
            logger.error("requests library is required for Telegram notifications. Install it with: pip install requests")
            return
        
        message = (
            f"❌ <b>Cronjob Failed</b>\n\n"
            f"<b>Task:</b> {execution.task_name} ({execution.task_code})\n"
            f"<b>Date:</b> {execution.execution_date}\n"
            f"<b>Started:</b> {execution.started.strftime('%Y-%m-%d %H:%M:%S')}\n"
            f"<b>Error Code:</b> {execution.error_code or 'N/A'}\n\n"
            f"<b>Error:</b>\n{error_message[:1000]}"
        )
        
        payload = {
            'chat_id': self.chat_id,
            'text': message,
            'parse_mode': 'HTML'
        }
        
        try:
            response = requests.post(self.api_url, json=payload, timeout=10)
            response.raise_for_status()
            logger.info(f"Telegram notification sent for failed task {execution.task_name}")
        except Exception as e:
            logger.error(f"Failed to send Telegram notification: {e}")


class NotificationManager:
    """Manages notifications for cronjob events."""
    
    def __init__(self):
        self.backends: List[NotificationBackend] = []
        self._load_backends()
    
    def _load_backends(self):
        """Load configured notification backends."""
        config = getattr(settings, 'CRONJOB_UTILS', {}).get('NOTIFICATIONS', {})
        
        on_failure = config.get('on_failure', [])
        
        if 'email' in on_failure:
            try:
                email_config = config.get('email', {})
                self.backends.append(EmailBackend(email_config))
            except Exception as e:
                logger.error(f"Failed to initialize Email backend: {e}")
        
        if 'slack' in on_failure:
            try:
                slack_config = config.get('slack', {})
                self.backends.append(SlackBackend(slack_config))
            except Exception as e:
                logger.error(f"Failed to initialize Slack backend: {e}")
        
        if 'telegram' in on_failure:
            try:
                telegram_config = config.get('telegram', {})
                self.backends.append(TelegramBackend(telegram_config))
            except Exception as e:
                logger.error(f"Failed to initialize Telegram backend: {e}")
    
    def notify_failure(self, execution: CronExecution, error_message: str):
        """Notify stakeholders of failure."""
        for backend in self.backends:
            try:
                backend.notify_failure(execution, error_message)
            except Exception as e:
                logger.error(f"Notification backend {backend.__class__.__name__} failed: {e}")
    
    def notify_success(self, execution: CronExecution, message: str = ''):
        """Notify stakeholders of success (if configured)."""
        config = getattr(settings, 'CRONJOB_UTILS', {}).get('NOTIFICATIONS', {})
        on_success = config.get('on_success', [])
        
        if not on_success:
            return
        
        for backend in self.backends:
            if backend.__class__.__name__.lower().replace('backend', '') in on_success:
                try:
                    backend.notify_success(execution, message)
                except Exception as e:
                    logger.error(f"Notification backend {backend.__class__.__name__} failed: {e}")
