"""
Celery tasks for communication credits and Twilio integration.
"""
import logging
from celery import shared_task
from django.conf import settings
from django.utils import timezone
from datetime import timedelta

logger = logging.getLogger(__name__)


@shared_task
def sync_twilio_usage_all_tenants():
    """
    Sync Twilio usage for all tenants with subaccounts.

    Runs periodically (e.g., hourly) to:
    1. Fetch usage from each Twilio subaccount
    2. Calculate charges with markup
    3. Deduct from tenant credits
    """
    from smoothschedule.identity.core.models import Tenant

    tenants = Tenant.objects.exclude(twilio_subaccount_sid='')

    synced = 0
    errors = 0

    for tenant in tenants:
        try:
            sync_twilio_usage_for_tenant.delay(tenant.id)
            synced += 1
        except Exception as e:
            logger.error(f"Error queuing sync for tenant {tenant.name}: {e}")
            errors += 1

    logger.info(f"Queued Twilio sync for {synced} tenants, {errors} errors")
    return {'synced': synced, 'errors': errors}


@shared_task
def sync_twilio_usage_for_tenant(tenant_id):
    """
    Sync Twilio usage for a specific tenant.

    Fetches usage from Twilio API and deducts from credits.
    """
    from smoothschedule.identity.core.models import Tenant
    from .models import CommunicationCredits

    try:
        tenant = Tenant.objects.get(id=tenant_id)
    except Tenant.DoesNotExist:
        logger.error(f"Tenant {tenant_id} not found")
        return {'error': 'Tenant not found'}

    if not tenant.twilio_subaccount_sid:
        return {'error': 'No Twilio subaccount configured'}

    # Get or create credits for tenant
    credits, created = CommunicationCredits.objects.get_or_create(tenant=tenant)

    try:
        from twilio.rest import Client

        # Initialize Twilio client with subaccount credentials
        client = Client(
            tenant.twilio_subaccount_sid,
            tenant.twilio_subaccount_auth_token
        )

        # Get this month's usage
        today = timezone.now().date()
        first_of_month = today.replace(day=1)

        records = client.usage.records.this_month.list()

        # Calculate total Twilio cost
        total_twilio_cost_cents = 0
        usage_breakdown = {}

        for record in records:
            cost_cents = int(float(record.price) * 100)
            total_twilio_cost_cents += cost_cents
            usage_breakdown[record.category] = {
                'usage': str(record.usage),
                'cost_cents': cost_cents,
            }

        # Apply markup (e.g., 50% margin)
        # This should come from the tenant's subscription plan
        markup_multiplier = getattr(settings, 'COMMS_MARKUP_MULTIPLIER', 1.5)
        total_with_markup_cents = int(total_twilio_cost_cents * markup_multiplier)

        # Calculate new charges since last sync
        new_charges = total_with_markup_cents - credits.billed_usage_cents

        if new_charges > 0:
            # Deduct from credits
            credits.deduct(
                new_charges,
                f"Twilio usage for {first_of_month.strftime('%B %Y')}",
                reference_type='twilio_sync',
                reference_id=f"{first_of_month.isoformat()}"
            )

            # Update sync tracking
            credits.billed_usage_cents = total_with_markup_cents

        # Update sync info
        credits.last_twilio_sync_at = timezone.now()
        credits.twilio_sync_period_start = first_of_month
        credits.twilio_raw_usage_cents = total_twilio_cost_cents
        credits.save(update_fields=[
            'last_twilio_sync_at', 'twilio_sync_period_start',
            'twilio_raw_usage_cents', 'billed_usage_cents'
        ])

        logger.info(
            f"Synced Twilio usage for {tenant.name}: "
            f"${total_twilio_cost_cents/100:.2f} raw, "
            f"${total_with_markup_cents/100:.2f} with markup, "
            f"${new_charges/100:.2f} new charges"
        )

        return {
            'tenant': tenant.name,
            'raw_cost_cents': total_twilio_cost_cents,
            'billed_cents': total_with_markup_cents,
            'new_charges_cents': new_charges,
            'usage_breakdown': usage_breakdown,
        }

    except Exception as e:
        logger.error(f"Error syncing Twilio usage for {tenant.name}: {e}")
        return {'error': str(e)}


@shared_task
def send_low_balance_warning(credits_id):
    """
    Send low balance warning email to tenant.
    """
    from .models import CommunicationCredits
    from django.core.mail import send_mail

    try:
        credits = CommunicationCredits.objects.select_related('tenant').get(id=credits_id)
    except CommunicationCredits.DoesNotExist:
        return {'error': 'Credits not found'}

    tenant = credits.tenant

    # Get tenant owner's email
    owner = tenant.users.filter(role='owner').first()
    if not owner:
        logger.warning(f"No owner found for tenant {tenant.name}")
        return {'error': 'No owner email'}

    subject = f"Low Communication Credits Balance - {tenant.name}"
    message = f"""
Hi {owner.first_name or owner.username},

Your communication credits balance for {tenant.name} is running low.

Current Balance: ${credits.balance_cents/100:.2f}
Warning Threshold: ${credits.low_balance_warning_cents/100:.2f}

{"Auto-reload is ENABLED and will trigger at $" + f"{credits.auto_reload_threshold_cents/100:.2f}" if credits.auto_reload_enabled else "Auto-reload is NOT enabled. Please add credits to avoid service interruption."}

To add credits or manage your settings, visit your Communication Settings page.

Best regards,
SmoothSchedule Team
"""

    try:
        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,
            [owner.email],
            fail_silently=False,
        )
        logger.info(f"Sent low balance warning to {owner.email} for {tenant.name}")
        return {'sent_to': owner.email}
    except Exception as e:
        logger.error(f"Error sending low balance warning: {e}")
        return {'error': str(e)}


@shared_task
def process_auto_reload(credits_id):
    """
    Process auto-reload of credits.

    Charges the stored payment method and adds credits.
    """
    from .models import CommunicationCredits
    import stripe

    try:
        credits = CommunicationCredits.objects.select_related('tenant').get(id=credits_id)
    except CommunicationCredits.DoesNotExist:
        return {'error': 'Credits not found'}

    if not credits.auto_reload_enabled:
        return {'error': 'Auto-reload not enabled'}

    if not credits.stripe_payment_method_id:
        return {'error': 'No payment method'}

    if credits.balance_cents > credits.auto_reload_threshold_cents:
        return {'skipped': 'Balance above threshold'}

    tenant = credits.tenant
    amount_cents = credits.auto_reload_amount_cents

    try:
        # Get Stripe API key from platform settings
        from smoothschedule.platform.admin.models import PlatformSettings
        platform_settings = PlatformSettings.get_instance()
        stripe.api_key = platform_settings.get_stripe_secret_key()

        # Create payment intent and confirm
        payment_intent = stripe.PaymentIntent.create(
            amount=amount_cents,
            currency='usd',
            payment_method=credits.stripe_payment_method_id,
            confirm=True,
            description=f"Communication credits reload for {tenant.name}",
            metadata={
                'tenant_id': str(tenant.id),
                'tenant_name': tenant.name,
                'type': 'comms_credits_reload',
            },
            # Auto-confirm with the stored payment method
            automatic_payment_methods={
                'enabled': True,
                'allow_redirects': 'never',
            },
        )

        if payment_intent.status == 'succeeded':
            # Add credits
            credits.add_credits(
                amount_cents,
                transaction_type='auto_reload',
                stripe_charge_id=payment_intent.id,
                description=f"Auto-reload: ${amount_cents/100:.2f}"
            )

            logger.info(
                f"Auto-reloaded ${amount_cents/100:.2f} for {tenant.name}, "
                f"new balance: ${credits.balance_cents/100:.2f}"
            )

            return {
                'success': True,
                'amount_cents': amount_cents,
                'new_balance_cents': credits.balance_cents,
                'payment_intent_id': payment_intent.id,
            }
        else:
            logger.error(f"Payment failed for {tenant.name}: {payment_intent.status}")
            return {'error': f"Payment status: {payment_intent.status}"}

    except stripe.error.CardError as e:
        logger.error(f"Card error for {tenant.name}: {e.error.message}")
        return {'error': f"Card error: {e.error.message}"}
    except Exception as e:
        logger.error(f"Error processing auto-reload for {tenant.name}: {e}")
        return {'error': str(e)}


@shared_task
def bill_proxy_phone_numbers():
    """
    Monthly task to bill tenants for assigned proxy phone numbers.
    """
    from .models import ProxyPhoneNumber, CommunicationCredits

    today = timezone.now()
    first_of_month = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)

    # Get all assigned numbers that haven't been billed this month
    numbers = ProxyPhoneNumber.objects.filter(
        status=ProxyPhoneNumber.Status.ASSIGNED,
        is_active=True,
    ).exclude(
        last_billed_at__gte=first_of_month
    ).select_related('assigned_tenant')

    billed = 0
    errors = 0

    for number in numbers:
        tenant = number.assigned_tenant
        if not tenant:
            continue

        try:
            credits, _ = CommunicationCredits.objects.get_or_create(tenant=tenant)

            # Deduct monthly fee
            result = credits.deduct(
                number.monthly_fee_cents,
                f"Proxy number {number.phone_number} - {today.strftime('%B %Y')}",
                reference_type='proxy_number',
                reference_id=number.phone_number,
            )

            if result:
                number.last_billed_at = today
                number.save(update_fields=['last_billed_at', 'updated_at'])
                billed += 1
                logger.info(
                    f"Billed ${number.monthly_fee_cents/100:.2f} for {number.phone_number} "
                    f"to {tenant.name}"
                )
            else:
                logger.warning(
                    f"Insufficient credits for {tenant.name} to bill {number.phone_number}"
                )
                errors += 1

        except Exception as e:
            logger.error(f"Error billing {number.phone_number}: {e}")
            errors += 1

    logger.info(f"Billed {billed} proxy numbers, {errors} errors")
    return {'billed': billed, 'errors': errors}


@shared_task
def expire_masked_sessions():
    """
    Close expired masked sessions and release proxy numbers.
    """
    from .models import MaskedSession

    expired = MaskedSession.objects.filter(
        status=MaskedSession.Status.ACTIVE,
        expires_at__lt=timezone.now()
    )

    count = 0
    for session in expired:
        session.status = MaskedSession.Status.EXPIRED
        session.closed_at = timezone.now()
        session.save(update_fields=['status', 'closed_at', 'updated_at'])

        # Release proxy number if reserved
        if session.proxy_number:
            from .models import ProxyPhoneNumber
            if session.proxy_number.status == ProxyPhoneNumber.Status.RESERVED:
                session.proxy_number.status = ProxyPhoneNumber.Status.AVAILABLE
                session.proxy_number.save(update_fields=['status', 'updated_at'])

        count += 1

    if count:
        logger.info(f"Expired {count} masked sessions")

    return {'expired': count}


@shared_task
def create_twilio_subaccount(tenant_id):
    """
    Create a Twilio subaccount for a tenant.

    Called when SMS/calling is first enabled for a tenant.
    """
    from smoothschedule.identity.core.models import Tenant
    from twilio.rest import Client

    try:
        tenant = Tenant.objects.get(id=tenant_id)
    except Tenant.DoesNotExist:
        return {'error': 'Tenant not found'}

    if tenant.twilio_subaccount_sid:
        return {'skipped': 'Subaccount already exists'}

    try:
        # Get master Twilio credentials from settings
        master_sid = getattr(settings, 'TWILIO_ACCOUNT_SID', '')
        master_token = getattr(settings, 'TWILIO_AUTH_TOKEN', '')

        if not master_sid or not master_token:
            return {'error': 'Twilio master credentials not configured'}

        client = Client(master_sid, master_token)

        # Create subaccount
        subaccount = client.api.accounts.create(
            friendly_name=f"SmoothSchedule - {tenant.name}"
        )

        # Save to tenant
        tenant.twilio_subaccount_sid = subaccount.sid
        tenant.twilio_subaccount_auth_token = subaccount.auth_token
        tenant.save(update_fields=[
            'twilio_subaccount_sid', 'twilio_subaccount_auth_token'
        ])

        logger.info(f"Created Twilio subaccount for {tenant.name}: {subaccount.sid}")

        return {
            'success': True,
            'subaccount_sid': subaccount.sid,
        }

    except Exception as e:
        logger.error(f"Error creating Twilio subaccount for {tenant.name}: {e}")
        return {'error': str(e)}
