"""
Built-in automations for common automated tasks.

These automations are registered automatically and available out-of-the-box.
"""

from typing import Any, Dict
from django.core.mail import send_mail
from django.conf import settings
from django.utils import timezone
from django.db.models import Count, Q
from datetime import timedelta
import logging

from .registry import BaseAutomation, register_automation, AutomationExecutionError

logger = logging.getLogger(__name__)


@register_automation
class SendEmailAutomation(BaseAutomation):
    """Send a custom email to specified recipients"""

    name = "send_email"
    display_name = "Send Email"
    description = "Send a custom email message to one or more recipients"
    category = "communication"

    config_schema = {
        'recipients': {
            'type': 'list',
            'required': True,
            'description': 'List of email addresses',
        },
        'subject': {
            'type': 'string',
            'required': True,
            'description': 'Email subject line',
        },
        'message': {
            'type': 'text',
            'required': True,
            'description': 'Email message body',
        },
        'from_email': {
            'type': 'string',
            'required': False,
            'description': 'Sender email (uses default if not specified)',
        },
    }

    def execute(self, context: Dict[str, Any]) -> Dict[str, Any]:
        recipients = self.config.get('recipients', [])
        subject = self.config.get('subject', '')
        message = self.config.get('message', '')
        from_email = self.config.get('from_email', settings.DEFAULT_FROM_EMAIL)

        if not recipients:
            raise AutomationExecutionError("No recipients specified")

        try:
            send_mail(
                subject=subject,
                message=message,
                from_email=from_email,
                recipient_list=recipients,
                fail_silently=False,
            )
            return {
                'success': True,
                'message': f"Email sent to {len(recipients)} recipient(s)",
                'data': {'recipient_count': len(recipients)},
            }
        except Exception as e:
            raise AutomationExecutionError(f"Failed to send email: {e}")


@register_automation
class CleanupOldEventsAutomation(BaseAutomation):
    """Clean up old completed or canceled events"""

    name = "cleanup_old_events"
    display_name = "Clean Up Old Events"
    description = "Delete old completed or canceled events to keep database tidy"
    category = "maintenance"

    config_schema = {
        'days_old': {
            'type': 'integer',
            'required': False,
            'default': 90,
            'description': 'Delete events older than this many days (default: 90)',
        },
        'statuses': {
            'type': 'list',
            'required': False,
            'default': ['COMPLETED', 'CANCELED'],
            'description': 'Event statuses to clean up',
        },
        'dry_run': {
            'type': 'boolean',
            'required': False,
            'default': False,
            'description': 'If true, only count events without deleting',
        },
    }

    def execute(self, context: Dict[str, Any]) -> Dict[str, Any]:
        from smoothschedule.scheduling.schedule.models import Event

        days_old = self.config.get('days_old', 90)
        statuses = self.config.get('statuses', ['COMPLETED', 'CANCELED'])
        dry_run = self.config.get('dry_run', False)

        cutoff_date = timezone.now() - timedelta(days=days_old)

        events_query = Event.objects.filter(
            end_time__lt=cutoff_date,
            status__in=statuses,
        )

        count = events_query.count()

        if not dry_run and count > 0:
            events_query.delete()
            message = f"Deleted {count} old event(s)"
        else:
            message = f"Found {count} old event(s)" + (" (dry run, not deleted)" if dry_run else "")

        return {
            'success': True,
            'message': message,
            'data': {
                'count': count,
                'dry_run': dry_run,
                'days_old': days_old,
            },
        }


@register_automation
class DailyReportAutomation(BaseAutomation):
    """Generate and send a daily business report"""

    name = "daily_report"
    display_name = "Daily Report"
    description = "Generate a daily summary report of appointments and send via email"
    category = "reporting"

    config_schema = {
        'recipients': {
            'type': 'list',
            'required': True,
            'description': 'Email addresses to receive the report',
        },
        'include_upcoming': {
            'type': 'boolean',
            'required': False,
            'default': True,
            'description': 'Include upcoming appointments for today',
        },
        'include_completed': {
            'type': 'boolean',
            'required': False,
            'default': True,
            'description': 'Include completed appointments from yesterday',
        },
    }

    def execute(self, context: Dict[str, Any]) -> Dict[str, Any]:
        from smoothschedule.scheduling.schedule.models import Event

        business = context.get('business')
        recipients = self.config.get('recipients', [])

        if not recipients:
            raise AutomationExecutionError("No recipients specified")

        # Get today's date range
        today = timezone.now().date()
        today_start = timezone.make_aware(timezone.datetime.combine(today, timezone.datetime.min.time()))
        today_end = timezone.make_aware(timezone.datetime.combine(today, timezone.datetime.max.time()))

        # Get yesterday's date range
        yesterday = today - timedelta(days=1)
        yesterday_start = timezone.make_aware(timezone.datetime.combine(yesterday, timezone.datetime.min.time()))
        yesterday_end = timezone.make_aware(timezone.datetime.combine(yesterday, timezone.datetime.max.time()))

        # Build report
        report_lines = [
            f"Daily Report for {business.name if business else 'Business'}",
            f"Generated at: {timezone.now().strftime('%Y-%m-%d %H:%M')}",
            "",
        ]

        if self.config.get('include_upcoming', True):
            upcoming = Event.objects.filter(
                start_time__gte=today_start,
                start_time__lte=today_end,
                status='SCHEDULED',
            ).count()
            report_lines.extend([
                f"Today's Upcoming Appointments: {upcoming}",
                "",
            ])

        if self.config.get('include_completed', True):
            completed = Event.objects.filter(
                start_time__gte=yesterday_start,
                start_time__lte=yesterday_end,
                status__in=['COMPLETED', 'PAID'],
            ).count()
            canceled = Event.objects.filter(
                start_time__gte=yesterday_start,
                start_time__lte=yesterday_end,
                status='CANCELED',
            ).count()
            report_lines.extend([
                f"Yesterday's Summary:",
                f"  - Completed: {completed}",
                f"  - Canceled: {canceled}",
                "",
            ])

        report_body = "\n".join(report_lines)

        try:
            send_mail(
                subject=f"Daily Report - {today.strftime('%Y-%m-%d')}",
                message=report_body,
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=recipients,
                fail_silently=False,
            )
            return {
                'success': True,
                'message': f"Daily report sent to {len(recipients)} recipient(s)",
                'data': {'recipient_count': len(recipients)},
            }
        except Exception as e:
            raise AutomationExecutionError(f"Failed to send report: {e}")


@register_automation
class AppointmentReminderAutomation(BaseAutomation):
    """Send reminder emails/SMS for upcoming appointments"""

    name = "appointment_reminder"
    display_name = "Appointment Reminder"
    description = "Send reminders to customers about upcoming appointments"
    category = "communication"

    config_schema = {
        'hours_before': {
            'type': 'integer',
            'required': False,
            'default': 24,
            'description': 'Send reminder this many hours before appointment',
        },
        'method': {
            'type': 'choice',
            'choices': ['email', 'sms', 'both'],
            'required': False,
            'default': 'email',
            'description': 'How to send reminders',
        },
        'message_template': {
            'type': 'text',
            'required': False,
            'description': 'Custom message template (uses default if not specified)',
        },
    }

    def execute(self, context: Dict[str, Any]) -> Dict[str, Any]:
        from smoothschedule.scheduling.schedule.models import Event
        from smoothschedule.platform.admin.tasks import send_appointment_reminder_email

        hours_before = self.config.get('hours_before', 24)
        method = self.config.get('method', 'email')

        # Calculate time window
        now = timezone.now()
        reminder_start = now + timedelta(hours=hours_before - 1)
        reminder_end = now + timedelta(hours=hours_before + 1)

        # Find events in the reminder window
        upcoming_events = Event.objects.filter(
            start_time__gte=reminder_start,
            start_time__lte=reminder_end,
            status=Event.Status.SCHEDULED,
        ).prefetch_related('participants__customer')

        reminders_sent = 0
        reminders_failed = 0

        for event in upcoming_events:
            # Get customer emails from participants
            for participant in event.participants.all():
                if participant.customer and hasattr(participant.customer, 'email'):
                    customer_email = participant.customer.email
                    if customer_email:
                        if method in ['email', 'both']:
                            # Queue email reminder via Celery
                            send_appointment_reminder_email.delay(
                                event_id=event.id,
                                customer_email=customer_email,
                                hours_before=hours_before
                            )
                            reminders_sent += 1
                            logger.info(f"Queued email reminder for {customer_email} - event: {event.title}")

                        if method in ['sms', 'both']:
                            # SMS would go here via Twilio
                            # For now, just log the intent
                            logger.info(f"Would send SMS reminder to customer for event: {event.title}")

        return {
            'success': True,
            'message': f"Queued {reminders_sent} reminder(s)",
            'data': {
                'reminders_queued': reminders_sent,
                'reminders_failed': reminders_failed,
                'hours_before': hours_before,
                'method': method,
            },
        }


@register_automation
class BackupDatabaseAutomation(BaseAutomation):
    """Create a database backup"""

    name = "backup_database"
    display_name = "Backup Database"
    description = "Create a backup of the tenant's database schema"
    category = "maintenance"

    config_schema = {
        'backup_location': {
            'type': 'string',
            'required': False,
            'description': 'Custom backup location path',
        },
        'compress': {
            'type': 'boolean',
            'required': False,
            'default': True,
            'description': 'Compress the backup file',
        },
    }

    def execute(self, context: Dict[str, Any]) -> Dict[str, Any]:
        business = context.get('business')

        # This is a placeholder - actual implementation would use pg_dump
        # or Django's dumpdata management command
        logger.info(f"Would create backup for business: {business}")

        return {
            'success': True,
            'message': "Database backup created successfully",
            'data': {
                'backup_file': '/backups/placeholder.sql.gz',
                'size_mb': 0,
            },
        }


@register_automation
class WebhookAutomation(BaseAutomation):
    """Call an external webhook URL"""

    name = "webhook"
    display_name = "Webhook"
    description = "Make an HTTP request to an external webhook URL"
    category = "integration"

    config_schema = {
        'url': {
            'type': 'url',
            'required': True,
            'description': 'Webhook URL to call',
        },
        'method': {
            'type': 'choice',
            'choices': ['GET', 'POST', 'PUT', 'PATCH'],
            'required': False,
            'default': 'POST',
            'description': 'HTTP method',
        },
        'headers': {
            'type': 'dict',
            'required': False,
            'description': 'Custom HTTP headers',
        },
        'payload': {
            'type': 'dict',
            'required': False,
            'description': 'JSON payload to send',
        },
    }

    def execute(self, context: Dict[str, Any]) -> Dict[str, Any]:
        import requests

        url = self.config.get('url')
        method = self.config.get('method', 'POST').upper()
        headers = self.config.get('headers', {})
        payload = self.config.get('payload', {})

        if not url:
            raise AutomationExecutionError("Webhook URL is required")

        try:
            response = requests.request(
                method=method,
                url=url,
                json=payload,
                headers=headers,
                timeout=30,
            )
            response.raise_for_status()

            return {
                'success': True,
                'message': f"Webhook called successfully (status: {response.status_code})",
                'data': {
                    'status_code': response.status_code,
                    'response': response.text[:500],  # Truncate response
                },
            }
        except requests.RequestException as e:
            raise AutomationExecutionError(f"Webhook request failed: {e}")
