import os
import time
import json
import logging
from django.utils import timezone
from chatapp.utils.social_sender import send_outgoing_social_message
from chatapp.models import ChatMessage, WebhookTestLog, Company

logger = logging.getLogger(__name__)

# ── Tuning constants ──────────────────────────────────────────────────────────
SWEEP_INTERVAL_SECONDS = 3          # How often the worker wakes up (reduced for faster recovery)
OUTGOING_CUTOFF_SECONDS = 20        # Retry outgoing if still pending after N secs (primary send is instant now)
INCOMING_CUTOFF_SECONDS = 20        # Retry incoming if still pending after N secs
MAX_OUTGOING_ATTEMPTS = 5           # Give up on outgoing after this many tries
MAX_INCOMING_ATTEMPTS = 3           # Give up on incoming after this many tries
# ─────────────────────────────────────────────────────────────────────────────


def extract_message_from_log(log):
    """
    Parses a WebhookTestLog raw_payload (JSON) to extract routing details.
    Handles both live event payloads and Facebook Developer Portal sample payloads.
    """
    try:
        body = json.loads(log.raw_payload)
    except Exception:
        return None

    # ── Facebook ───────────────────────────────────────────────────────────
    if log.source == 'facebook':
        if 'entry' in body:
            for entry in body.get('entry', []):
                page_id = entry.get('id')
                for evt in entry.get('messaging', []):
                    msg = evt.get('message', {})
                    if msg.get('text'):
                        return {
                            'page_id': page_id,
                            'visitor_id': f"fb_{evt['sender']['id']}",
                            'message_text': msg['text'],
                            'meta_message_id': msg.get('mid'),
                        }
        elif 'sample' in body:
            value = body.get('sample', {}).get('value', {})
            sender_id  = value.get('sender', {}).get('id')
            recipient_id = value.get('recipient', {}).get('id')
            msg = value.get('message', {})
            if sender_id and recipient_id and msg.get('text'):
                return {
                    'page_id': recipient_id,
                    'visitor_id': f"fb_{sender_id}",
                    'message_text': msg['text'],
                    'meta_message_id': msg.get('mid'),
                }

    # ── WhatsApp ───────────────────────────────────────────────────────────
    elif log.source == 'whatsapp':
        if 'entry' in body:
            for entry in body.get('entry', []):
                for change in entry.get('changes', []):
                    value = change.get('value', {})
                    phone_id = value.get('metadata', {}).get('phone_number_id')
                    for msg in value.get('messages', []):
                        if msg.get('type') == 'text' and msg.get('text'):
                            return {
                                'phone_number_id': phone_id,
                                'visitor_id': f"wa_{msg['from']}",
                                'message_text': msg['text']['body'],
                                'meta_message_id': msg.get('id'),
                            }

    return None


def _sweep_outgoing():
    """Retry outgoing social messages that failed or are still pending."""
    cutoff = timezone.now() - timezone.timedelta(seconds=OUTGOING_CUTOFF_SECONDS)
    qs = ChatMessage.objects.filter(
        sender__in=['bot', 'agent'],
        delivery_status__in=['pending', 'failed'],
        delivery_attempts__lt=MAX_OUTGOING_ATTEMPTS,
        created_at__lt=cutoff,
    ).only('id', 'visitor_id')

    for msg in qs:
        if msg.visitor_id and (
            msg.visitor_id.startswith('fb_') or msg.visitor_id.startswith('wa_')
        ):
            logger.info("Worker retrying outgoing message id=%s", msg.id)
            send_outgoing_social_message(msg.id)


def _sweep_incoming():
    """Retry incoming webhook logs that are stuck pending or failed."""
    from chatapp.views import process_incoming_social_message

    cutoff = timezone.now() - timezone.timedelta(seconds=INCOMING_CUTOFF_SECONDS)
    qs = WebhookTestLog.objects.filter(
        reply_status__in=['pending', 'failed'],
        processing_attempts__lt=MAX_INCOMING_ATTEMPTS,
        created_at__lt=cutoff,
    )

    for log in qs:
        msg_details = extract_message_from_log(log)
        if not msg_details:
            log.reply_status = 'ignored'
            log.save(update_fields=['reply_status'])
            continue

        company = None
        if log.source == 'facebook' and 'page_id' in msg_details:
            company = Company.objects.filter(
                fb_page_id=msg_details['page_id'],
                fb_messenger_enabled=True,
            ).first()
        elif log.source == 'whatsapp' and 'phone_number_id' in msg_details:
            company = Company.objects.filter(
                wa_phone_number_id=msg_details['phone_number_id'],
                whatsapp_enabled=True,
            ).first()

        if not company:
            log.reply_status = 'failed'
            log.processing_attempts += 1
            log.save(update_fields=['reply_status', 'processing_attempts'])
            continue

        logger.info(
            "Worker processing incoming log id=%s for company '%s'",
            log.id, company.name,
        )
        log.processing_attempts += 1
        log.save(update_fields=['processing_attempts'])

        process_incoming_social_message(
            company.id,
            msg_details['visitor_id'],
            msg_details['message_text'],
            meta_message_id=msg_details.get('meta_message_id'),
            webhook_log_id=log.id,
        )


def run_queue_worker_loop():
    """
    Background daemon loop.
    Sweeps every SWEEP_INTERVAL_SECONDS for stuck outgoing and incoming messages.
    """
    logger.info(
        "ChatLab Queue Worker started (interval=%ds, outgoing_cutoff=%ds, incoming_cutoff=%ds)",
        SWEEP_INTERVAL_SECONDS, OUTGOING_CUTOFF_SECONDS, INCOMING_CUTOFF_SECONDS,
    )

    while True:
        try:
            _sweep_outgoing()
        except Exception as e:
            logger.error("Worker sweep_outgoing error: %s", e)

        try:
            _sweep_incoming()
        except Exception as e:
            logger.error("Worker sweep_incoming error: %s", e)

        time.sleep(SWEEP_INTERVAL_SECONDS)
