from celery import shared_task
from django.db.models import Exists, OuterRef
from django.db import transaction

from apps.calls.models import Call
from apps.calls.constants import BotType
from apps.calls.services.catch_phrase import CatchPhraseFillService
from apps.companies.models import CallCatchPhrase
import logging


logger = logging.getLogger(__name__)


@shared_task(
    bind=True,
    max_retries=3,
    default_retry_delay=30,
    name="apps.calls.tasks.process_catch_phrases_for_call"
)
def process_catch_phrases_for_call(self, call_id: int):
    """
    Process catchphrases for a SINGLE call.
    Safe to call multiple times (idempotent).
    """
    try:
        call = (
            Call.objects
            .filter(
                id=call_id,
                bot_type=BotType.SERVICE_BOT.value,
                transcript__gt=""
            )
            .first()
        )

        if not call:
            logger.info(f"[CatchPhrase] Call {call_id} skipped (not eligible)")
            return 0

        if CallCatchPhrase.objects.filter(call=call).exists():
            logger.info(f"[CatchPhrase] Call {call_id} already processed")
            return 0

        with transaction.atomic():
            created = CatchPhraseFillService.fill_call(call)

        logger.info(
            f"[CatchPhrase] Call {call_id} processed "
            f"(phrases created={created})"
        )

        return created

    except Exception as exc:
        logger.exception(
            f"[CatchPhrase] Failed processing call {call_id}: {exc}"
        )
        raise self.retry(exc=exc)

@shared_task(
    bind=True,
    max_retries=3,
    default_retry_delay=60,
    name='apps.calls.tasks.backfill_catch_phrases_for_calls'
)
def backfill_catch_phrases_for_calls(self, call_ids=None):
    try:
        qs = Call.objects.filter(
            bot_type=BotType.SERVICE_BOT.value,
            transcript__isnull=False
        ).annotate(
            has_phrases=Exists(
                CallCatchPhrase.objects.filter(call_id=OuterRef('pk'))
            )
        ).filter(
            has_phrases=False
        )

        if call_ids:
            qs = qs.filter(id__in=call_ids)

        total_calls = qs.count()
        logger.info(f"Starting catch phrase backfill for {total_calls} calls")

        processed = 0
        created = 0

        for call in qs.iterator(chunk_size=100):
            with transaction.atomic():
                count = CatchPhraseFillService.fill_call(call)
                created += count
                processed += 1

                logger.info(
                    f"Processed {processed}/{total_calls} calls "
                    f"(phrases created: {created})"
                )

        logger.info(
            f"Backfill complete. "
            f"Calls processed={processed}, phrases created={created}"
        )

        return {
            "processed_calls": processed,
            "phrases_created": created
        }

    except Exception as exc:
        logger.exception(f"Failed to enqueue fill: {exc}")
        raise self.retry(exc=exc)
