"""Live engagement statistics endpoints (Python parity with PHP).

  POST /api/stats/heartbeat        any authed user → record device ping
  GET  /api/admin/stats/live       admin → live watchers (last 90 s)
  GET  /api/admin/stats/installs   admin → total installs / DAU / WAU
"""
from __future__ import annotations

from datetime import datetime, timezone
from typing import Optional

from fastapi import APIRouter, Depends
from pydantic import BaseModel

from core.auth import get_current_user, get_db, require_admin

router = APIRouter(prefix="/api", tags=["stats"])


class HeartbeatIn(BaseModel):
    device_id: Optional[str] = None
    channel: Optional[str] = None
    kind: str = "live"


@router.post("/stats/heartbeat")
async def heartbeat(body: HeartbeatIn, user=Depends(get_current_user)):
    db = get_db()
    now_ts = int(datetime.now(timezone.utc).timestamp())
    device_id = body.device_id or f"web-{user['id'][:12]}"
    await db.stats_heartbeats.update_one(
        {"device_id": device_id},
        {
            "$set": {
                "device_id": device_id,
                "user_id": user["id"],
                "channel": body.channel or "",
                "kind": body.kind or "live",
                "updated_at_ts": now_ts,
                "updated_at_iso": datetime.now(timezone.utc).isoformat(),
            },
            "$setOnInsert": {"created_at_ts": now_ts},
        },
        upsert=True,
    )
    return {"ok": True, "device_id": device_id}


@router.get("/admin/stats/live")
async def live_stats(window: int = 90, _admin=Depends(require_admin)):
    db = get_db()
    window = max(30, min(600, window))
    now_ts = int(datetime.now(timezone.utc).timestamp())
    threshold = now_ts - window

    live_watchers = await db.stats_heartbeats.count_documents(
        {"updated_at_ts": {"$gte": threshold}}
    )

    by_kind: dict[str, int] = {}
    async for row in db.stats_heartbeats.aggregate(
        [
            {"$match": {"updated_at_ts": {"$gte": threshold}}},
            {"$group": {"_id": "$kind", "count": {"$sum": 1}}},
        ]
    ):
        by_kind[str(row.get("_id") or "unknown")] = int(row["count"])

    top_channels: list[dict] = []
    async for row in db.stats_heartbeats.aggregate(
        [
            {
                "$match": {
                    "updated_at_ts": {"$gte": threshold},
                    "channel": {"$ne": ""},
                }
            },
            {"$group": {"_id": "$channel", "viewers": {"$sum": 1}}},
            {"$sort": {"viewers": -1}},
            {"$limit": 10},
        ]
    ):
        top_channels.append({"channel": str(row["_id"]), "viewers": int(row["viewers"])})

    return {
        "live_watchers": live_watchers,
        "window_seconds": window,
        "by_kind": by_kind,
        "top_channels": top_channels,
        "as_of": datetime.now(timezone.utc).isoformat(),
    }


@router.get("/admin/stats/installs")
async def install_stats(_admin=Depends(require_admin)):
    db = get_db()
    now_ts = int(datetime.now(timezone.utc).timestamp())
    day = now_ts - 86400
    week = now_ts - 7 * 86400

    # 2026-06: "installed users" in admin panel should be resilient even
    # when push tokens are absent/disabled. We use BOTH data sources:
    #   1) FCM tokens (push-capable installs)
    #   2) device_trials hardware_id fingerprints (actual app installs)
    # and expose both + deduped totals.
    total_fcm = await db.fcm_tokens.count_documents({})
    active_fcm = await db.fcm_tokens.count_documents({"is_active": True})
    total_trials = await db.device_trials.count_documents({})

    # Approximate active trial devices by last_seen_at (ISO string) over 30d.
    # Lexicographic compare is safe for timezone-aware ISO-8601 strings.
    month_iso = datetime.fromtimestamp(now_ts - 30 * 86400, timezone.utc).isoformat()
    active_trials_30d = await db.device_trials.count_documents(
        {"last_seen_at": {"$gte": month_iso}}
    )

    # Merge by hardware/device ids where possible for a best-effort unique count.
    trial_ids = {
        str(d.get("hardware_id", ""))
        for d in await db.device_trials.find({}, {"_id": 0, "hardware_id": 1}).to_list(length=None)
        if d.get("hardware_id")
    }
    fcm_ids = {
        str(d.get("device_id", ""))
        for d in await db.fcm_tokens.find({}, {"_id": 0, "device_id": 1}).to_list(length=None)
        if d.get("device_id")
    }
    merged_unique = len(trial_ids.union(fcm_ids))

    async def _unique_devices(threshold: int) -> int:
        async for row in db.stats_heartbeats.aggregate(
            [
                {"$match": {"updated_at_ts": {"$gte": threshold}}},
                {"$group": {"_id": "$device_id"}},
                {"$count": "n"},
            ]
        ):
            return int(row.get("n", 0))
        return 0

    by_platform: dict[str, int] = {}
    async for row in db.fcm_tokens.aggregate(
        [{"$group": {"_id": "$platform", "count": {"$sum": 1}}}]
    ):
        by_platform[str(row.get("_id") or "unknown")] = int(row["count"])

    return {
        # Backward-compatible fields consumed by current frontend widget.
        "total_installs": merged_unique or total_trials or total_fcm,
        "active_installs": max(active_fcm, active_trials_30d),
        "dau": await _unique_devices(day),
        "wau": await _unique_devices(week),
        # New explicit breakdown fields for admin clarity.
        "total_installs_trial_devices": total_trials,
        "active_installs_trial_devices_30d": active_trials_30d,
        "total_installs_fcm_tokens": total_fcm,
        "active_installs_fcm_tokens": active_fcm,
        "total_installs_merged_unique": merged_unique,
        "by_platform": by_platform,
        "as_of": datetime.now(timezone.utc).isoformat(),
    }
