"""
Webhook Notifier for Health Check Alerts
Sends alerts to Slack, Discord, or Microsoft Teams
"""

import json
import os
from pathlib import Path
from typing import Dict, List, Optional

from django.core.management.base import BaseCommand
from django.conf import settings
from django.utils.timezone import now

import requests


class WebhookFormatter:
    """Format messages for different webhook types"""
    
    @staticmethod
    def format_slack(portal: str, health_data: Dict) -> Dict:
        """Format for Slack webhook"""
        status = health_data['overall_status']
        score = health_data['overall_score']
        
        # Color based on status
        color_map = {
            'healthy': '#36a64f',
            'degraded': '#ff9900',
            'critical': '#ff0000',
            'failing': '#8b0000'
        }
        
        color = color_map.get(status, '#cccccc')
        
        # Build message
        fields = [
            {
                'title': 'Overall Score',
                'value': f'{score:.1f}/100',
                'short': True
            },
            {
                'title': 'Status',
                'value': status.upper(),
                'short': True
            }
        ]
        
        # Add critical issues
        if 'critical_issues' in health_data and health_data['critical_issues']:
            issues_text = '\n'.join([
                f"• {issue['title']}: {issue['description']}"
                for issue in health_data['critical_issues'][:3]
            ])
            fields.append({
                'title': f'Critical Issues ({len(health_data["critical_issues"])})',
                'value': issues_text,
                'short': False
            })
        
        # Add quick fix
        if health_data.get('recommendations'):
            fields.append({
                'title': 'Quick Fix',
                'value': health_data['recommendations'][0],
                'short': False
            })
        
        return {
            'attachments': [{
                'color': color,
                'title': f'🏥 Health Alert: {portal}',
                'fields': fields,
                'footer': 'Advanced Health Monitor',
                'ts': int(now().timestamp())
            }]
        }
    
    @staticmethod
    def format_discord(portal: str, health_data: Dict) -> Dict:
        """Format for Discord webhook"""
        status = health_data['overall_status']
        score = health_data['overall_score']
        
        # Color based on status
        color_map = {
            'healthy': 0x36a64f,
            'degraded': 0xff9900,
            'critical': 0xff0000,
            'failing': 0x8b0000
        }
        
        color = color_map.get(status, 0xcccccc)
        
        # Build embed
        embed = {
            'title': f'🏥 Health Alert: {portal}',
            'color': color,
            'fields': [
                {
                    'name': 'Overall Score',
                    'value': f'{score:.1f}/100',
                    'inline': True
                },
                {
                    'name': 'Status',
                    'value': status.upper(),
                    'inline': True
                }
            ],
            'timestamp': now().isoformat()
        }
        
        # Add critical issues
        if health_data.get('critical_issues'):
            issues_text = '\n'.join([
                f"• **{issue['title']}**: {issue['description']}"
                for issue in health_data['critical_issues'][:3]
            ])
            embed['fields'].append({
                'name': f'Critical Issues ({len(health_data["critical_issues"])})',
                'value': issues_text,
                'inline': False
            })
        
        # Add recommendation
        if health_data.get('recommendations'):
            embed['fields'].append({
                'name': '💡 Quick Fix',
                'value': health_data['recommendations'][0],
                'inline': False
            })
        
        return {'embeds': [embed]}
    
    @staticmethod
    def format_teams(portal: str, health_data: Dict) -> Dict:
        """Format for Microsoft Teams webhook"""
        status = health_data['overall_status']
        score = health_data['overall_score']
        
        # Theme color based on status
        color_map = {
            'healthy': '36a64f',
            'degraded': 'ff9900',
            'critical': 'ff0000',
            'failing': '8b0000'
        }
        
        theme_color = color_map.get(status, 'cccccc')
        
        # Build message card
        sections = [
            {
                'activityTitle': f'🏥 Health Alert: {portal}',
                'activitySubtitle': f'Status: {status.upper()}',
                'facts': [
                    {
                        'name': 'Overall Score',
                        'value': f'{score:.1f}/100'
                    },
                    {
                        'name': 'Status',
                        'value': status.upper()
                    }
                ],
                'markdown': True
            }
        ]
        
        # Add critical issues
        if health_data.get('critical_issues'):
            issues_text = '\n\n'.join([
                f"**{issue['title']}**  \n{issue['description']}"
                for issue in health_data['critical_issues'][:3]
            ])
            sections.append({
                'title': f'Critical Issues ({len(health_data["critical_issues"])})',
                'text': issues_text
            })
        
        # Add recommendation
        if health_data.get('recommendations'):
            sections.append({
                'title': '💡 Quick Fix',
                'text': health_data['recommendations'][0]
            })
        
        return {
            '@type': 'MessageCard',
            '@context': 'https://schema.org/extensions',
            'themeColor': theme_color,
            'summary': f'Health Alert: {portal}',
            'sections': sections
        }


class Command(BaseCommand):
    """
    Send health check alerts to webhooks
    
    Usage:
        python manage.py manual_notify --json health_report.json
        python manage.py manual_notify --portal otodom
        python manage.py manual_notify --all --threshold-error 0.15
    """
    
    help = 'Send health check alerts to configured webhooks'
    
    def add_arguments(self, parser):
        parser.add_argument(
            '--json',
            type=str,
            help='Path to health report JSON file'
        )
        parser.add_argument(
            '--portal',
            type=str,
            help='Check specific portal and notify if unhealthy'
        )
        parser.add_argument(
            '--all',
            action='store_true',
            help='Check all portals and notify for unhealthy ones'
        )
        parser.add_argument(
            '--threshold-error',
            type=float,
            default=0.15,
            help='Error rate threshold (default: 0.15)'
        )
        parser.add_argument(
            '--threshold-score',
            type=float,
            default=70.0,
            help='Health score threshold (default: 70)'
        )
        parser.add_argument(
            '--min-pages',
            type=int,
            default=10,
            help='Minimum pages to consider (default: 10)'
        )
        parser.add_argument(
            '--webhook-url',
            type=str,
            help='Override webhook URL'
        )
        parser.add_argument(
            '--webhook-type',
            choices=['slack', 'discord', 'teams', 'auto'],
            default='auto',
            help='Webhook type (default: auto-detect)'
        )
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='Print webhook payload without sending'
        )
        parser.add_argument(
            '--channel',
            type=str,
            help='Optional channel/mention (e.g., @here, @channel)'
        )
    
    def handle(self, *args, **options):
        json_file = options['json']
        portal = options['portal']
        check_all = options['all']
        webhook_url = options['webhook_url'] or os.getenv('DEBUGGER_WEBHOOK_URL')
        webhook_type = options['webhook_type']
        dry_run = options['dry_run']
        threshold_error = options['threshold_error']
        threshold_score = options['threshold_score']
        min_pages = options['min_pages']
        channel = options['channel']
        
        if not webhook_url and not dry_run:
            self.stderr.write(self.style.ERROR(
                'Webhook URL not configured. Set DEBUGGER_WEBHOOK_URL environment variable or use --webhook-url'
            ))
            exit(1)
        
        # Auto-detect webhook type
        if webhook_type == 'auto' and webhook_url:
            if 'slack.com' in webhook_url:
                webhook_type = 'slack'
            elif 'discord.com' in webhook_url or 'discordapp.com' in webhook_url:
                webhook_type = 'discord'
            elif 'office.com' in webhook_url or 'webhook.office' in webhook_url:
                webhook_type = 'teams'
            else:
                webhook_type = 'slack'  # Default
        
        # Load or generate health data
        if json_file:
            health_reports = self._load_json_report(json_file)
        elif portal:
            health_reports = [self._run_health_check(portal)]
        elif check_all:
            from your_app.models import SourceManual
            portals = SourceManual.objects.filter(enable=True).values_list('name', flat=True)
            health_reports = [self._run_health_check(p) for p in portals]
        else:
            self.stderr.write(self.style.ERROR('Must specify --json, --portal, or --all'))
            exit(1)
        
        # Filter unhealthy portals
        unhealthy_reports = [
            r for r in health_reports
            if self._is_unhealthy(r, threshold_error, threshold_score, min_pages)
        ]
        
        if not unhealthy_reports:
            self.stdout.write(self.style.SUCCESS('✅ All portals healthy, no alerts sent'))
            exit(0)
        
        # Send alerts
        alerts_sent = 0
        for report in unhealthy_reports:
            success = self._send_alert(
                report, 
                webhook_url, 
                webhook_type, 
                channel,
                dry_run
            )
            if success:
                alerts_sent += 1
        
        self.stdout.write(self.style.WARNING(
            f'⚠️  Sent {alerts_sent} alert(s) for unhealthy portals'
        ))
        
        # Exit with code 2 if any unhealthy
        exit(2)
    
    def _load_json_report(self, filepath: str) -> List[Dict]:
        """Load health report from JSON"""
        path = Path(settings.BASE_DIR) / filepath
        
        if not path.exists():
            self.stderr.write(self.style.ERROR(f'JSON file not found: {filepath}'))
            exit(1)
        
        with open(path, 'r') as f:
            data = json.load(f)
        
        return data.get('reports', [data])  # Handle both single and multi-report
    
    def _run_health_check(self, portal: str) -> Dict:
        """Run health check for portal"""
        from your_app.management.commands.advanced_health import AdvancedHealthManager
        
        manager = AdvancedHealthManager()
        report = manager.run_comprehensive_check(portal, hours=24)
        
        # Convert to dict
        return {
            'portal': report.portal,
            'overall_status': report.overall_status.value,
            'overall_score': report.overall_score,
            'timestamp': report.timestamp.isoformat(),
            'critical_issues': [
                {
                    'title': i.title,
                    'description': i.description,
                    'impact': i.impact,
                    'remediation_steps': i.remediation_steps
                }
                for i in report.issues if i.severity.value == 'critical'
            ],
            'recommendations': report.recommendations,
            'business_metrics': report.business_metrics
        }
    
    def _is_unhealthy(
        self, 
        report: Dict, 
        threshold_error: float,
        threshold_score: float,
        min_pages: int
    ) -> bool:
        """Check if portal is unhealthy"""
        # Check score threshold
        if report['overall_score'] < threshold_score:
            return True
        
        # Check for critical issues
        if report.get('critical_issues'):
            return True
        
        # Check status
        if report['overall_status'] in ['critical', 'failing']:
            return True
        
        return False
    
    def _send_alert(
        self,
        report: Dict,
        webhook_url: str,
        webhook_type: str,
        channel: Optional[str],
        dry_run: bool
    ) -> bool:
        """Send alert to webhook"""
        portal = report['portal']
        
        # Format message
        formatter = WebhookFormatter()
        if webhook_type == 'slack':
            payload = formatter.format_slack(portal, report)
            if channel:
                payload['text'] = f'{channel} Health Alert'
        elif webhook_type == 'discord':
            payload = formatter.format_discord(portal, report)
            if channel:
                payload['content'] = f'{channel} Health Alert'
        elif webhook_type == 'teams':
            payload = formatter.format_teams(portal, report)
        else:
            self.stderr.write(self.style.ERROR(f'Unknown webhook type: {webhook_type}'))
            return False
        
        if dry_run:
            self.stdout.write(self.style.WARNING(f'\n[DRY RUN] Would send to {webhook_type}:'))
            self.stdout.write(json.dumps(payload, indent=2))
            return True
        
        # Send webhook
        try:
            response = requests.post(
                webhook_url,
                json=payload,
                headers={'Content-Type': 'application/json'},
                timeout=10
            )
            
            if response.status_code in [200, 204]:
                self.stdout.write(self.style.SUCCESS(
                    f'✓ Alert sent for {portal}'
                ))
                return True
            else:
                self.stderr.write(self.style.ERROR(
                    f'✗ Failed to send alert for {portal}: {response.status_code} {response.text}'
                ))
                return False
                
        except Exception as e:
            self.stderr.write(self.style.ERROR(
                f'✗ Error sending alert for {portal}: {str(e)}'
            ))
            return False