"""
Dispatch Lucky Dip announcements across requested notification channels.

Supported channels:
  - in_app    : Notification model records (shown in bell icon / notification inbox)
  - push      : FCM push via registered UserDeviceToken records
  - email     : Sent via the active SMTP EmailConfig
  - whatsapp  : Meta Cloud API (must be enabled in platform settings)
  - sms       : Queued / logged (full SMS gateway dispatch requires celery worker)
"""

import logging

from django.contrib.auth import get_user_model
from django.utils import timezone

logger = logging.getLogger(__name__)
User = get_user_model()

# Default channels sent when admin does not specify anything
DEFAULT_CHANNELS: list[str] = ["in_app", "push"]


def dispatch_lucky_dip_announcement(lucky_dip, channels: list[str] | None = None) -> dict:
    """
    Send announcement notifications for `lucky_dip` over each requested channel.

    Args:
        lucky_dip: LuckyDip instance with announcement_title, announcement_message, draw_date set
        channels:  list of channel keys to send on (in_app, push, email, whatsapp, sms)

    Returns:
        dict with per-channel result counts
    """
    if not channels:
        channels = list(DEFAULT_CHANNELS)

    title = lucky_dip.announcement_title or lucky_dip.name
    message = lucky_dip.announcement_message or f"Lucky Dip draw is coming! Draw date: {lucky_dip.draw_date}"
    dip_id = str(lucky_dip.id)

    results: dict = {c: {"attempted": 0, "success": 0, "failed": 0} for c in channels}

    users = list(User.objects.filter(is_active=True))

    # ── In-App ────────────────────────────────────────────────────────────────
    if "in_app" in channels:
        from apps.notifications.models import Notification

        now = timezone.now()
        objs = [
            Notification(
                user=user,
                channel="in_app",
                recipient=user.mobile or user.email or str(user.id),
                subject=title,
                message=message,
                payload={"lucky_dip_id": dip_id, "type": "lucky_dip_announcement"},
                status="sent",
                provider="internal",
                sent_at=now,
                is_read=False,
            )
            for user in users
        ]
        created = Notification.objects.bulk_create(objs, ignore_conflicts=False)
        results["in_app"]["attempted"] = len(objs)
        results["in_app"]["success"] = len(created)

    # ── Push (FCM) ────────────────────────────────────────────────────────────
    if "push" in channels:
        from apps.notifications.delivery import _send_fcm_push
        from apps.notifications.models import UserDeviceToken

        tokens = list(
            UserDeviceToken.objects.filter(user__in=users, is_active=True).values_list("device_token", flat=True)
        )
        results["push"]["attempted"] = len(tokens)
        if tokens:
            data = {"lucky_dip_id": dip_id, "type": "lucky_dip_announcement"}
            success, failed = _send_fcm_push(tokens=tokens, title=title, body=message, data=data)
            results["push"]["success"] = success
            results["push"]["failed"] = failed
        else:
            logger.info("Lucky Dip push: no active device tokens registered.")

    # ── Email ─────────────────────────────────────────────────────────────────
    if "email" in channels:
        from apps.notifications.email_delivery import send_email_using_active_config

        email_recipients = [u.email for u in users if u.email and "@" in u.email]
        results["email"]["attempted"] = len(email_recipients)

        # Send in batches of 50 to avoid header size limits
        BATCH_SIZE = 50
        for i in range(0, len(email_recipients), BATCH_SIZE):
            batch = email_recipients[i : i + BATCH_SIZE]
            res = send_email_using_active_config(
                subject=title,
                message=message,
                recipient_list=batch,
                purpose="notification",
            )
            if res.get("ok"):
                results["email"]["success"] += len(batch)
            else:
                results["email"]["failed"] += len(batch)
                logger.warning("Lucky Dip email batch failed: %s", res.get("error"))

    # ── WhatsApp ──────────────────────────────────────────────────────────────
    if "whatsapp" in channels:
        from apps.notifications.whatsapp_service import send_whatsapp_message
        from apps.masterdata.platform_setting import PlatformSetting

        wa_enabled = PlatformSetting.get_bool("whatsapp_enabled", False)
        mobiles = [u.mobile for u in users if u.mobile]
        results["whatsapp"]["attempted"] = len(mobiles)

        if not wa_enabled:
            logger.warning("Lucky Dip WhatsApp: WhatsApp is disabled in platform settings.")
            results["whatsapp"]["failed"] = len(mobiles)
        else:
            for mobile in mobiles:
                try:
                    res = send_whatsapp_message(recipient=mobile, message_type="text", text=f"*{title}*\n\n{message}")
                    if res.get("ok"):
                        results["whatsapp"]["success"] += 1
                    else:
                        results["whatsapp"]["failed"] += 1
                except Exception as exc:
                    logger.warning("Lucky Dip WhatsApp send failed for %s: %s", mobile, exc)
                    results["whatsapp"]["failed"] += 1

    # ── SMS ───────────────────────────────────────────────────────────────────
    if "sms" in channels:
        from apps.masterdata.platform_setting import PlatformSetting

        mobiles = [u.mobile for u in users if u.mobile]
        results["sms"]["attempted"] = len(mobiles)

        # Dispatch via active gateway (Twilio / MSG91 / TextLocal)
        gateway = PlatformSetting.get_value("sms_active_gateway", "twilio") or "twilio"
        sms_text = f"{title}: {message}"

        for mobile in mobiles:
            try:
                sent = _send_sms(gateway=gateway, to=mobile, text=sms_text)
                if sent:
                    results["sms"]["success"] += 1
                else:
                    results["sms"]["failed"] += 1
            except Exception as exc:
                logger.warning("Lucky Dip SMS send failed for %s: %s", mobile, exc)
                results["sms"]["failed"] += 1

    logger.info(
        "Lucky Dip announcement dispatched: dip_id=%s channels=%s results=%s",
        dip_id,
        channels,
        results,
    )
    return results


def _send_sms(gateway: str, to: str, text: str) -> bool:
    """
    Best-effort SMS dispatch using the active gateway credentials from PlatformSetting.
    Returns True if sent successfully, False otherwise.
    """
    from apps.masterdata.platform_setting import PlatformSetting

    try:
        if gateway == "twilio":
            import os
            account_sid = PlatformSetting.get_value("sms_twilio_account_sid", "")
            auth_token = PlatformSetting.get_value("sms_twilio_auth_token", "")
            from_number = PlatformSetting.get_value("sms_twilio_from_number", "")
            if not all([account_sid, auth_token, from_number]):
                logger.warning("Twilio credentials incomplete — SMS skipped for %s", to)
                return False
            # Use requests instead of twilio SDK to keep it lightweight
            import requests as req
            url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json"
            resp = req.post(url, data={"From": from_number, "To": to, "Body": text}, auth=(account_sid, auth_token), timeout=10)
            return resp.status_code in {200, 201}

        elif gateway == "msg91":
            import requests as req
            auth_key = PlatformSetting.get_value("sms_msg91_auth_key", "")
            sender_id = PlatformSetting.get_value("sms_msg91_sender_id", "")
            route = PlatformSetting.get_value("sms_msg91_route", "4")
            if not auth_key:
                logger.warning("MSG91 auth_key not configured — SMS skipped for %s", to)
                return False
            import re
            digits = re.sub(r"[^0-9]", "", to)
            url = "https://api.msg91.com/api/v2/sendsms"
            payload = {
                "sender": sender_id,
                "route": route,
                "country": "91",
                "sms": [{"message": text, "to": [digits]}],
            }
            resp = req.post(url, json=payload, headers={"authkey": auth_key, "Content-Type": "application/json"}, timeout=10)
            return resp.status_code == 200

        elif gateway == "textlocal":
            import requests as req
            api_key = PlatformSetting.get_value("sms_textlocal_api_key", "")
            sender = PlatformSetting.get_value("sms_textlocal_sender", "TXTLCL")
            if not api_key:
                logger.warning("TextLocal api_key not configured — SMS skipped for %s", to)
                return False
            resp = req.post(
                "https://api.textlocal.in/send/",
                data={"apikey": api_key, "numbers": to, "message": text, "sender": sender},
                timeout=10,
            )
            return resp.status_code == 200

    except Exception as exc:
        logger.exception("SMS gateway error (%s) for %s: %s", gateway, to, exc)

    return False
