"""
World Cup fixture auto-notifications.

Triggers automatic push alerts when fixtures are changed from admin side:
1) on SAVE (new fixture inserted)
2) on important status updates (LIVE / GOAL)

Safe no-op when Firebase is unavailable or there are no active devices.
"""

from __future__ import annotations

import logging
from datetime import datetime, timezone
from typing import Any, Dict, List

from core.db import get_db

logger = logging.getLogger(__name__)


async def sync_and_notify_worldcup_fixtures(payload: Dict[str, Any]) -> Dict[str, Any]:
    db = get_db()

    incoming = payload.get("matches")
    if not isinstance(incoming, list):
        raise ValueError("matches must be an array")

    # Build a map of previous fixtures by id for change detection.
    prev_docs = await db.worldcup_fixtures.find({}, {"_id": 0}).to_list(length=None)
    prev_map: Dict[str, Dict[str, Any]] = {
        str(d.get("id")): d for d in prev_docs if d.get("id") is not None
    }

    now_iso = datetime.now(timezone.utc).isoformat()
    clean: List[Dict[str, Any]] = []
    notifications: List[Dict[str, Any]] = []

    for raw in incoming:
        if not isinstance(raw, dict):
            continue

        mid = str(raw.get("id") or "").strip()
        if not mid:
            continue

        item = {
            "id": mid,
            "kickoffIso": str(raw.get("kickoffIso") or ""),
            "status": str(raw.get("status") or "UPCOMING").upper(),
            "group": raw.get("group"),
            "venue": raw.get("venue"),
            "home": raw.get("home") or {},
            "away": raw.get("away") or {},
            "homeScore": raw.get("homeScore"),
            "awayScore": raw.get("awayScore"),
            "homePenalty": raw.get("homePenalty"),
            "awayPenalty": raw.get("awayPenalty"),
            "broadcaster": raw.get("broadcaster") or "",
            "liveLabel": raw.get("liveLabel") or "",
            "updated_at": now_iso,
        }
        clean.append(item)

        prev = prev_map.get(mid)
        if prev is None:
            notifications.append(_build_save_notification(item))
            continue

        prev_status = str(prev.get("status") or "").upper()
        new_status = item["status"]

        # Rule C: fire when status transitions to LIVE or GOAL-like signal.
        if prev_status != new_status and new_status in {"LIVE", "GOAL"}:
            notifications.append(_build_live_goal_notification(item, new_status))

    # Replace full fixture set atomically from admin source of truth.
    await db.worldcup_fixtures.delete_many({})
    if clean:
        await db.worldcup_fixtures.insert_many(clean)

    # Deduplicate notifications by (title, body) for one admin save action.
    unique: Dict[str, Dict[str, Any]] = {}
    for n in notifications:
        k = f"{n.get('title','')}|{n.get('body','')}"
        unique[k] = n

    sent_meta: List[Dict[str, Any]] = []
    for msg in unique.values():
        try:
            meta = await _broadcast(msg)
            sent_meta.append(meta)
        except Exception as e:  # noqa: BLE001
            logger.warning("WorldCup auto-notify failed: %s", e)
            sent_meta.append({"queued": False, "error": str(e), **msg})

    return {
        "ok": True,
        "saved": len(clean),
        "notifications": sent_meta,
    }


def _teams(item: Dict[str, Any]) -> str:
    h = (item.get("home") or {}).get("name") or "Home"
    a = (item.get("away") or {}).get("name") or "Away"
    return f"{h} vs {a}"


def _build_save_notification(item: Dict[str, Any]) -> Dict[str, Any]:
    title = "World Cup Match Added"
    body = f"{_teams(item)} is now scheduled. Tap Watch on to open live stream."
    broadcaster = str(item.get("broadcaster") or "").strip()
    data = {
        "type": "worldcup_save",
        "match_id": str(item.get("id") or ""),
        "kickoff_iso": str(item.get("kickoffIso") or ""),
    }
    if broadcaster:
        data["channel_name"] = broadcaster
    return {
        "title": title,
        "body": body,
        "route": "/world-cup",
        "action_label": "Watch on",
        "data": data,
    }


def _build_live_goal_notification(item: Dict[str, Any], status: str) -> Dict[str, Any]:
    title = "Live Now" if status == "LIVE" else "Goal Alert"
    score = f"{item.get('homeScore', 0)}-{item.get('awayScore', 0)}"
    body = f"{_teams(item)} {('is live' if status == 'LIVE' else f'update {score}')}."
    broadcaster = str(item.get("broadcaster") or "").strip()
    data = {
        "type": "worldcup_live" if status == "LIVE" else "worldcup_goal",
        "match_id": str(item.get("id") or ""),
    }
    if broadcaster:
        data["channel_name"] = broadcaster
    return {
        "title": title,
        "body": body,
        "route": "/world-cup",
        "action_label": "Watch on",
        "data": data,
    }


async def _broadcast(payload: Dict[str, Any]) -> Dict[str, Any]:
    # Reuse backend notification sender to keep one push pipeline.
    from routes import notifications as notifications_module  # local import avoids cycles

    db = get_db()
    docs = await db.fcm_tokens.find(
        {"is_active": True}, {"_id": 0, "token": 1, "device_id": 1, "user_id": 1}
    ).to_list(length=20000)

    if not docs:
        return {"queued": False, "reason": "no_active_devices", **payload}

    # Ensure Firebase app is initialised in this worker context too.
    notifications_module._ensure_firebase()
    if not getattr(notifications_module, "_FIREBASE_READY", False):
        return {
            "queued": False,
            "reason": "firebase_not_configured",
            "error": getattr(notifications_module, "_FIREBASE_ERROR", "unknown"),
            **payload,
        }

    await notifications_module._send_broadcast(payload, docs)
    return {"queued": True, "total_tokens": len(docs), **payload}
