"""
Celery tasks for contract management.
Handles email notifications, reminders, PDF generation, and expiration.
"""
import logging
from celery import shared_task
from django.utils import timezone
from django.template.loader import render_to_string
from django.conf import settings
from datetime import timedelta
from smoothschedule.communication.messaging.email_service import send_html_email

logger = logging.getLogger(__name__)


@shared_task(bind=True, max_retries=3)
def send_contract_email(self, contract_id):
    """
    Send initial contract signing request email to customer.

    Args:
        contract_id: ID of the Contract to send

    Returns:
        dict: Result with success status and details
    """
    from .models import Contract
    from django.db import connection
    from smoothschedule.identity.core.models import Tenant

    try:
        contract = Contract.objects.select_related('customer', 'template').get(id=contract_id)
    except Contract.DoesNotExist:
        logger.error(f"Contract {contract_id} not found")
        return {'success': False, 'error': 'Contract not found'}

    # Get tenant info
    tenant = None
    if hasattr(connection, 'tenant'):
        tenant = connection.tenant
    else:
        try:
            tenant = Tenant.objects.get(schema_name=connection.schema_name)
        except Tenant.DoesNotExist:
            logger.warning(f"Could not find tenant for contract {contract_id}")

    business_name = tenant.name if tenant else 'SmoothSchedule'
    from_email = tenant.contact_email if tenant and tenant.contact_email else settings.DEFAULT_FROM_EMAIL

    # Get signing URL
    signing_url = contract.get_signing_url()

    # Render email content
    context = {
        'contract': contract,
        'customer': contract.customer,
        'business_name': business_name,
        'signing_url': signing_url,
        'expires_at': contract.expires_at,
    }

    subject = f"Please Sign: {contract.title}"
    html_message = render_to_string('contracts/emails/signing_request.html', context)
    plain_message = render_to_string('contracts/emails/signing_request.txt', context)

    try:
        send_html_email(
            subject=subject,
            message=plain_message,
            from_email=from_email,
            recipient_list=[contract.customer.email],
            html_message=html_message,
            fail_silently=False,
        )

        # Update contract
        contract.sent_at = timezone.now()
        contract.save(update_fields=['sent_at'])

        logger.info(f"Sent contract signing email for contract {contract_id} to {contract.customer.email}")
        
        return {
            'success': True,
            'contract_id': contract_id,
            'recipient': contract.customer.email,
        }

    except Exception as e:
        logger.error(f"Failed to send contract email for {contract_id}: {str(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_contract_reminder(self, contract_id):
    """
    Send reminder email for pending contract.

    Args:
        contract_id: ID of the Contract to remind about

    Returns:
        dict: Result with success status
    """
    from .models import Contract
    from django.db import connection
    from smoothschedule.identity.core.models import Tenant

    try:
        contract = Contract.objects.select_related('customer').get(id=contract_id)
    except Contract.DoesNotExist:
        logger.error(f"Contract {contract_id} not found")
        return {'success': False, 'error': 'Contract not found'}

    # Only send reminder if contract is still pending
    if contract.status != 'PENDING':
        logger.info(f"Skipping reminder for contract {contract_id} - status is {contract.status}")
        return {'success': False, 'skipped': True, 'reason': f'Contract status is {contract.status}'}

    # Get tenant info
    tenant = None
    if hasattr(connection, 'tenant'):
        tenant = connection.tenant
    else:
        try:
            tenant = Tenant.objects.get(schema_name=connection.schema_name)
        except Tenant.DoesNotExist:
            pass

    business_name = tenant.name if tenant else 'SmoothSchedule'
    from_email = tenant.contact_email if tenant and tenant.contact_email else settings.DEFAULT_FROM_EMAIL

    # Calculate days until expiration
    days_until_expiry = None
    if contract.expires_at:
        days_until_expiry = (contract.expires_at - timezone.now()).days

    context = {
        'contract': contract,
        'customer': contract.customer,
        'business_name': business_name,
        'signing_url': contract.get_signing_url(),
        'expires_at': contract.expires_at,
        'days_until_expiry': days_until_expiry,
    }

    subject = f"Reminder: Please Sign {contract.title}"
    html_message = render_to_string('contracts/emails/reminder.html', context)
    plain_message = render_to_string('contracts/emails/reminder.txt', context)

    try:
        send_html_email(
            subject=subject,
            message=plain_message,
            from_email=from_email,
            recipient_list=[contract.customer.email],
            html_message=html_message,
            fail_silently=False,
        )

        logger.info(f"Sent contract reminder for {contract_id} to {contract.customer.email}")
        
        return {'success': True, 'contract_id': contract_id}

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


@shared_task(bind=True, max_retries=3)
def send_contract_signed_emails(self, contract_id):
    """
    Send confirmation emails after contract is signed.
    Sends to both customer and business owner.

    Args:
        contract_id: ID of the signed Contract

    Returns:
        dict: Result with success status
    """
    from .models import Contract
    from django.db import connection
    from smoothschedule.identity.core.models import Tenant
    from smoothschedule.identity.users.models import User

    try:
        contract = Contract.objects.select_related('customer', 'signature').get(id=contract_id)
    except Contract.DoesNotExist:
        logger.error(f"Contract {contract_id} not found")
        return {'success': False, 'error': 'Contract not found'}

    if contract.status != 'SIGNED':
        logger.warning(f"Contract {contract_id} is not signed, skipping confirmation emails")
        return {'success': False, 'skipped': True}

    # Get tenant info
    tenant = None
    if hasattr(connection, 'tenant'):
        tenant = connection.tenant
    else:
        try:
            tenant = Tenant.objects.get(schema_name=connection.schema_name)
        except Tenant.DoesNotExist:
            pass

    business_name = tenant.name if tenant else 'SmoothSchedule'
    from_email = tenant.contact_email if tenant and tenant.contact_email else settings.DEFAULT_FROM_EMAIL

    context = {
        'contract': contract,
        'signature': contract.signature,
        'customer': contract.customer,
        'business_name': business_name,
    }

    results = {'customer_sent': False, 'business_sent': False}

    # Send to customer
    try:
        subject = f"Contract Signed: {contract.title}"
        html_message = render_to_string('contracts/emails/signed_customer.html', context)
        plain_message = render_to_string('contracts/emails/signed_customer.txt', context)

        send_html_email(
            subject=subject,
            message=plain_message,
            from_email=from_email,
            recipient_list=[contract.customer.email],
            html_message=html_message,
            fail_silently=False,
        )
        
        results['customer_sent'] = True
        logger.info(f"Sent signed confirmation to customer {contract.customer.email}")

    except Exception as e:
        logger.error(f"Failed to send customer confirmation for {contract_id}: {str(e)}")

    # Send to business owner(s)
    try:
        # Get business owners
        owners = User.objects.filter(role='owner')
        owner_emails = [owner.email for owner in owners if owner.email]

        if owner_emails:
            subject = f"Contract Signed by {contract.customer.get_full_name() or contract.customer.email}"
            html_message = render_to_string('contracts/emails/signed_business.html', context)
            plain_message = render_to_string('contracts/emails/signed_business.txt', context)

            send_html_email(
                subject=subject,
                message=plain_message,
                from_email=from_email,
                recipient_list=owner_emails,
                html_message=html_message,
                fail_silently=False,
            )
            
            results['business_sent'] = True
            logger.info(f"Sent signed notification to business owners: {owner_emails}")

    except Exception as e:
        logger.error(f"Failed to send business notification for {contract_id}: {str(e)}")

    return {'success': True, 'results': results}


@shared_task(bind=True, max_retries=3)
def generate_contract_pdf(self, contract_id):
    """
    Generate PDF for a signed contract and save to storage.

    Args:
        contract_id: ID of the signed Contract

    Returns:
        dict: Result with PDF path
    """
    from .models import Contract
    from .pdf_service import ContractPDFService

    try:
        contract = Contract.objects.select_related('customer', 'signature').get(id=contract_id)
    except Contract.DoesNotExist:
        logger.error(f"Contract {contract_id} not found")
        return {'success': False, 'error': 'Contract not found'}

    if contract.status != 'SIGNED':
        logger.warning(f"Contract {contract_id} is not signed, cannot generate PDF")
        return {'success': False, 'error': 'Contract must be signed'}

    try:
        pdf_path = ContractPDFService.save_contract_pdf(contract)
        
        logger.info(f"Generated PDF for contract {contract_id}: {pdf_path}")
        
        return {
            'success': True,
            'contract_id': contract_id,
            'pdf_path': pdf_path,
        }

    except Exception as e:
        logger.error(f"Failed to generate PDF for {contract_id}: {str(e)}", exc_info=True)
        raise self.retry(exc=e, countdown=60 * (2 ** self.request.retries))


@shared_task
def check_expired_contracts():
    """
    Periodic task to check for expired contracts and mark them as EXPIRED.

    Should run daily.

    Returns:
        dict: Number of contracts marked as expired
    """
    from .models import Contract

    now = timezone.now()
    
    # Find pending contracts that have expired
    expired_contracts = Contract.objects.filter(
        status='PENDING',
        expires_at__lte=now,
        expires_at__isnull=False,
    )

    count = expired_contracts.count()
    
    # Mark them as expired
    expired_contracts.update(status='EXPIRED')

    logger.info(f"Marked {count} contracts as expired")
    
    return {'expired_count': count}


@shared_task
def send_pending_reminders():
    """
    Periodic task to send reminders for pending contracts.
    Sends reminder 3 days before expiration.

    Should run daily.

    Returns:
        dict: Number of reminders sent
    """
    from .models import Contract

    # Calculate the reminder window (contracts expiring in 3 days)
    now = timezone.now()
    reminder_date = now + timedelta(days=3)
    
    # Find pending contracts expiring in approximately 3 days
    # Use a 12-hour window around the 3-day mark
    contracts_to_remind = Contract.objects.filter(
        status='PENDING',
        expires_at__gte=reminder_date - timedelta(hours=12),
        expires_at__lte=reminder_date + timedelta(hours=12),
        expires_at__isnull=False,
    ).select_related('customer')

    count = 0
    for contract in contracts_to_remind:
        try:
            send_contract_reminder.delay(contract.id)
            count += 1
        except Exception as e:
            logger.error(f"Failed to queue reminder for contract {contract.id}: {str(e)}")

    logger.info(f"Queued {count} contract reminders")
    
    return {'reminders_queued': count}
