"""
Celery tasks for platform admin operations.
"""
from celery import shared_task
from django.core.mail import send_mail, EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings
from django.utils.html import strip_tags
import logging

logger = logging.getLogger(__name__)


def get_base_url():
    """Get the base URL for the platform."""
    # In production, this should come from settings
    return getattr(settings, 'PLATFORM_BASE_URL', 'http://platform.lvh.me:5173')


@shared_task(bind=True, max_retries=3)
def send_tenant_invitation_email(self, invitation_id: int):
    """
    Send an invitation email to a prospective tenant.

    Args:
        invitation_id: ID of the TenantInvitation to send
    """
    from .models import TenantInvitation

    try:
        invitation = TenantInvitation.objects.select_related('invited_by').get(id=invitation_id)
    except TenantInvitation.DoesNotExist:
        logger.error(f"TenantInvitation {invitation_id} not found")
        return {'success': False, 'error': 'Invitation not found'}

    # Don't send if already accepted or expired
    if invitation.status != TenantInvitation.Status.PENDING:
        logger.info(f"Skipping email for invitation {invitation_id} - status is {invitation.status}")
        return {'success': False, 'error': f'Invitation status is {invitation.status}'}

    if not invitation.is_valid():
        logger.info(f"Skipping email for invitation {invitation_id} - invitation expired")
        return {'success': False, 'error': 'Invitation expired'}

    try:
        # Build the invitation URL
        base_url = get_base_url()
        invitation_url = f"{base_url}/tenant-onboard?token={invitation.token}"

        # Email context
        context = {
            'invitation': invitation,
            'invitation_url': invitation_url,
            'inviter_name': invitation.invited_by.get_full_name() or invitation.invited_by.email if invitation.invited_by else 'SmoothSchedule Team',
            'suggested_business_name': invitation.suggested_business_name or 'your new business',
            'personal_message': invitation.personal_message,
            'expires_at': invitation.expires_at,
        }

        # Render HTML email
        html_content = render_to_string('platform_admin/emails/tenant_invitation.html', context)
        text_content = strip_tags(html_content)

        # Subject line
        subject = f"You're invited to join SmoothSchedule!"
        if invitation.invited_by:
            inviter = invitation.invited_by.get_full_name() or invitation.invited_by.email
            subject = f"{inviter} has invited you to SmoothSchedule"

        # Send email
        from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@smoothschedule.com')

        email = EmailMultiAlternatives(
            subject=subject,
            body=text_content,
            from_email=from_email,
            to=[invitation.email],
        )
        email.attach_alternative(html_content, "text/html")
        email.send()

        logger.info(f"Sent invitation email to {invitation.email} for invitation {invitation_id}")
        return {'success': True, 'email': invitation.email}

    except Exception as e:
        logger.error(f"Failed to send invitation email for {invitation_id}: {e}", exc_info=True)
        # Retry with exponential backoff
        raise self.retry(exc=e, countdown=60 * (2 ** self.request.retries))


@shared_task(bind=True, max_retries=3)
def send_appointment_reminder_email(self, event_id: int, customer_email: str, hours_before: int = 24):
    """
    Send an appointment reminder email to a customer.

    Args:
        event_id: ID of the Event
        customer_email: Email address to send reminder to
        hours_before: Hours before the appointment (for context in email)
    """
    from smoothschedule.scheduling.schedule.models import Event

    try:
        event = Event.objects.select_related('created_by').prefetch_related(
            'participants'
        ).get(id=event_id)
    except Event.DoesNotExist:
        logger.error(f"Event {event_id} not found")
        return {'success': False, 'error': 'Event not found'}

    # Don't send for cancelled events
    if event.status == Event.Status.CANCELED:
        logger.info(f"Skipping reminder for event {event_id} - event is cancelled")
        return {'success': False, 'error': 'Event cancelled'}

    try:
        # Get resources/staff for the event
        staff_names = []
        for participant in event.participants.filter(role__in=['RESOURCE', 'STAFF']):
            if participant.content_object and hasattr(participant.content_object, 'name'):
                staff_names.append(participant.content_object.name)

        # Get business info from tenant
        from django.db import connection
        business_name = 'SmoothSchedule'
        if hasattr(connection, 'tenant'):
            business_name = connection.tenant.name

        # Email context
        context = {
            'event': event,
            'customer_email': customer_email,
            'business_name': business_name,
            'staff_names': staff_names,
            'hours_before': hours_before,
            'event_date': event.start_time.strftime('%A, %B %d, %Y'),
            'event_time': event.start_time.strftime('%I:%M %p'),
            'duration_minutes': int(event.duration.total_seconds() // 60) if hasattr(event.duration, 'total_seconds') else event.duration,
        }

        # Render HTML email
        html_content = render_to_string('schedule/emails/appointment_reminder.html', context)
        text_content = strip_tags(html_content)

        # Subject line
        subject = f"Reminder: Your appointment at {business_name} on {context['event_date']}"

        # Send email
        from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@smoothschedule.com')

        email = EmailMultiAlternatives(
            subject=subject,
            body=text_content,
            from_email=from_email,
            to=[customer_email],
        )
        email.attach_alternative(html_content, "text/html")
        email.send()

        logger.info(f"Sent appointment reminder to {customer_email} for event {event_id}")
        return {'success': True, 'email': customer_email, 'event_id': event_id}

    except Exception as e:
        logger.error(f"Failed to send appointment reminder for event {event_id}: {e}", exc_info=True)
        raise self.retry(exc=e, countdown=60 * (2 ** self.request.retries))


@shared_task
def send_bulk_appointment_reminders(hours_before: int = 24):
    """
    Find all appointments happening in X hours and send reminder emails.

    This is typically run periodically by Celery Beat.

    Args:
        hours_before: How many hours before the appointment to send reminders
    """
    from smoothschedule.scheduling.schedule.models import Event
    from django.utils import timezone
    from datetime import timedelta

    now = timezone.now()
    reminder_window_start = now + timedelta(hours=hours_before - 0.5)
    reminder_window_end = now + timedelta(hours=hours_before + 0.5)

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

    reminders_queued = 0
    for event in 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:
                    # Queue the reminder email
                    send_appointment_reminder_email.delay(
                        event_id=event.id,
                        customer_email=customer_email,
                        hours_before=hours_before
                    )
                    reminders_queued += 1

    logger.info(f"Queued {reminders_queued} appointment reminder emails for {hours_before}h window")
    return {'reminders_queued': reminders_queued, 'hours_before': hours_before}


@shared_task(bind=True, max_retries=3)
def sync_subscription_plan_to_tenants(self, plan_id: int):
    """
    Sync a subscription plan's permissions and limits to all tenants using that plan.

    This task is triggered when a SubscriptionPlan is updated, ensuring all tenants
    on that plan have their permissions and limits updated accordingly.

    Args:
        plan_id: ID of the SubscriptionPlan that was updated
    """
    from .models import SubscriptionPlan
    from smoothschedule.identity.core.models import Tenant

    try:
        plan = SubscriptionPlan.objects.get(id=plan_id)
    except SubscriptionPlan.DoesNotExist:
        logger.error(f"SubscriptionPlan {plan_id} not found")
        return {'success': False, 'error': 'Plan not found'}

    # Get all tenants using this plan
    tenants = Tenant.objects.filter(subscription_plan=plan)
    tenant_count = tenants.count()

    if tenant_count == 0:
        logger.info(f"No tenants found for plan {plan.name} (ID: {plan_id})")
        return {'success': True, 'tenants_updated': 0, 'plan_name': plan.name}

    logger.info(f"Syncing plan '{plan.name}' to {tenant_count} tenant(s)")

    # Mapping from plan.permissions JSON keys to Tenant boolean field names
    # Some plan keys differ from tenant field names
    permission_mapping = {
        # Plan JSON key -> Tenant field name
        'can_manage_oauth_credentials': 'can_manage_oauth_credentials',
        'can_accept_payments': 'can_accept_payments',
        'can_use_custom_domain': 'can_use_custom_domain',
        'can_white_label': 'can_white_label',
        'can_api_access': 'can_api_access',
        'video_conferencing': 'can_add_video_conferencing',
        'can_add_video_conferencing': 'can_add_video_conferencing',
        'can_connect_to_api': 'can_connect_to_api',
        'can_book_repeated_events': 'can_book_repeated_events',
        'can_require_2fa': 'can_require_2fa',
        'can_download_logs': 'can_download_logs',
        'can_delete_data': 'can_delete_data',
        # Communication - plan may use short names
        'sms_reminders': 'can_use_sms_reminders',
        'can_use_sms_reminders': 'can_use_sms_reminders',
        'masked_calling': 'can_use_masked_phone_numbers',
        'can_use_masked_phone_numbers': 'can_use_masked_phone_numbers',
        'can_use_pos': 'can_use_pos',
        'can_use_mobile_app': 'can_use_mobile_app',
        # Advanced features - plan may use short names
        'export_data': 'can_export_data',
        'can_export_data': 'can_export_data',
        'automations': 'can_use_automations',
        'can_use_automations': 'can_use_automations',
        'tasks': 'can_use_tasks',
        'can_use_tasks': 'can_use_tasks',
        'can_create_automations': 'can_create_automations',
        'webhooks': 'can_use_webhooks',
        'can_use_webhooks': 'can_use_webhooks',
        'calendar_sync': 'can_use_calendar_sync',
        'can_use_calendar_sync': 'can_use_calendar_sync',
        'contracts': 'can_use_contracts',
        'contracts_enabled': 'can_use_contracts',
        'can_use_contracts': 'can_use_contracts',
    }

    # Limit field mappings from plan.limits JSON to Tenant fields
    limit_fields = [
        'max_users',
        'max_resources',
    ]

    plan_permissions = plan.permissions or {}
    plan_limits = plan.limits or {}

    updated_count = 0
    errors = []

    for tenant in tenants:
        try:
            changed = False

            # Update permission fields using the mapping
            for plan_key, tenant_field in permission_mapping.items():
                if plan_key in plan_permissions:
                    new_value = bool(plan_permissions[plan_key])
                    if getattr(tenant, tenant_field, None) != new_value:
                        setattr(tenant, tenant_field, new_value)
                        changed = True

            # Update limit fields
            for field in limit_fields:
                if field in plan_limits:
                    new_value = int(plan_limits[field])
                    if getattr(tenant, field, None) != new_value:
                        setattr(tenant, field, new_value)
                        changed = True

            # Update subscription tier based on plan name
            tier_mapping = {
                'Free': 'FREE',
                'Starter': 'STARTER',
                'Professional': 'PROFESSIONAL',
                'Business': 'PROFESSIONAL',  # Map Business to Professional
                'Enterprise': 'ENTERPRISE',
            }
            new_tier = tier_mapping.get(plan.name)
            if new_tier and tenant.subscription_tier != new_tier:
                tenant.subscription_tier = new_tier
                changed = True

            if changed:
                tenant.save()
                updated_count += 1
                logger.debug(f"Updated tenant '{tenant.name}' (ID: {tenant.id})")

        except Exception as e:
            error_msg = f"Failed to update tenant {tenant.id}: {str(e)}"
            logger.error(error_msg)
            errors.append(error_msg)

    result = {
        'success': True,
        'plan_id': plan_id,
        'plan_name': plan.name,
        'tenants_found': tenant_count,
        'tenants_updated': updated_count,
    }

    if errors:
        result['errors'] = errors
        result['success'] = len(errors) < tenant_count  # Partial success

    logger.info(f"Completed sync for plan '{plan.name}': {updated_count}/{tenant_count} tenants updated")
    return result
