"""
Diagnostic: query Discord's entitlements API directly and report what it returns
right now. Compare against the local entitlements.db cache.

Usage (on the server):
    cd ~/GitHub/SREBOT_MEOW
    source ../SHARED/.venv/bin/activate
    python scripts/diag_entitlements.py

Targeted guild: 1379510072815779961 (bot owner's max-tier server).
"""
from __future__ import annotations

import asyncio
import os
import sqlite3
import sys
import time
from pathlib import Path

import aiohttp
from dotenv import load_dotenv

load_dotenv()

APPLICATION_ID = "1254679514466877540"
TARGET_GUILD = "1379510072815779961"
TOKEN = os.environ.get("DISCORD_KEY", "")
_storage_env = os.environ.get("STORAGE_VOL_PATH", "").strip()
if not _storage_env:
    raise RuntimeError("STORAGE_VOL_PATH must be set")
STORAGE = Path(_storage_env)
DB_PATH = STORAGE / "entitlements.db"


async def fetch_all_entitlements() -> tuple[list[dict], list[tuple[int, int, str, str]]]:
    """
    Returns (entitlements, page_logs).
    page_logs: list of (page_num, count, status, after_cursor)
    """
    if not TOKEN:
        print("ERROR: DISCORD_KEY env var not set", file=sys.stderr)
        sys.exit(1)

    headers = {"Authorization": f"Bot {TOKEN}"}
    url = f"https://discord.com/api/v10/applications/{APPLICATION_ID}/entitlements"
    params: dict[str, str] = {"exclude_ended": "true", "limit": "100"}

    all_ents: list[dict] = []
    page_logs: list[tuple[int, int, str, str]] = []
    page = 0
    after: str | None = None

    timeout = aiohttp.ClientTimeout(total=60)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        while True:
            page += 1
            q = dict(params)
            if after:
                q["after"] = after
            t0 = time.monotonic()
            async with session.get(url, headers=headers, params=q) as resp:
                elapsed = time.monotonic() - t0
                status = f"{resp.status} ({elapsed:.2f}s)"
                if resp.status != 200:
                    body = await resp.text()
                    page_logs.append((page, 0, status, after or ""))
                    print(f"[!] page {page} failed: {status}\n    {body[:300]}")
                    break
                batch = await resp.json()
            page_logs.append((page, len(batch), status, after or ""))
            all_ents.extend(batch)
            if len(batch) < 100:
                break
            # paginate forward by id
            after = batch[-1]["id"]
            # safety break
            if page > 50:
                print("[!] hit 50-page safety limit, stopping")
                break

    return all_ents, page_logs


def read_db_state() -> dict[str, int]:
    if not DB_PATH.exists():
        return {"db_missing": 1}
    conn = sqlite3.connect(str(DB_PATH))
    try:
        cur = conn.cursor()
        out: dict[str, int] = {}
        out["guild_entitlements_total"] = cur.execute("SELECT COUNT(*) FROM guild_entitlements").fetchone()[0]
        out["guild_entitlements_active"] = cur.execute("SELECT COUNT(*) FROM guild_entitlements WHERE status='active'").fetchone()[0]
        out["manual_entitlements_total"] = cur.execute("SELECT COUNT(*) FROM manual_entitlements").fetchone()[0]
        out["discord_entitlements_total"] = cur.execute("SELECT COUNT(*) FROM discord_entitlements").fetchone()[0]
        row = cur.execute("SELECT * FROM discord_entitlements WHERE guild_id=?", (TARGET_GUILD,)).fetchone()
        out["target_in_discord_table"] = 1 if row else 0
        return out
    finally:
        conn.close()


async def main() -> None:
    print("=" * 70)
    print(f"Discord Entitlements Diagnostic — {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}")
    print("=" * 70)

    print(f"\n[1] Local DB state ({DB_PATH}):")
    for k, v in read_db_state().items():
        print(f"    {k}: {v}")

    print("\n[2] Discord API: GET /applications/{app_id}/entitlements?exclude_ended=true")
    ents, pages = await fetch_all_entitlements()

    print("\n    Page log:")
    for p, n, status, after in pages:
        print(f"      page {p:>2}  count={n:>3}  status={status:<18}  after={after}")

    print(f"\n    Total entitlements returned: {len(ents)}")

    # Group by guild
    by_guild: dict[str, list[dict]] = {}
    for e in ents:
        gid = e.get("guild_id")
        if gid:
            by_guild.setdefault(str(gid), []).append(e)

    print(f"    Unique guild_ids: {len(by_guild)}")
    print(f"    Entitlements with NULL guild_id: {sum(1 for e in ents if not e.get('guild_id'))}")

    # Status breakdown
    deleted = sum(1 for e in ents if e.get("deleted"))
    consumed = sum(1 for e in ents if e.get("consumed"))
    starts_in_future = sum(1 for e in ents if e.get("starts_at") and e["starts_at"] > time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()))
    ends_in_past = sum(1 for e in ents if e.get("ends_at") and e["ends_at"] < time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()))
    print(f"    deleted={deleted}  consumed={consumed}  starts_in_future={starts_in_future}  ends_in_past={ends_in_past}")

    print(f"\n[3] Target guild {TARGET_GUILD}:")
    target_ents = by_guild.get(TARGET_GUILD, [])
    if not target_ents:
        print(f"    *** NOT FOUND in Discord API response ***")
        # Show sample of what we DID get to confirm we're not just paginating wrong
        sample_guilds = list(by_guild.keys())[:5]
        print(f"    Sample of guild_ids returned: {sample_guilds}")
    else:
        for e in target_ents:
            print(f"    id={e.get('id')}  sku_id={e.get('sku_id')}  type={e.get('type')}  "
                  f"deleted={e.get('deleted')}  starts_at={e.get('starts_at')}  ends_at={e.get('ends_at')}")

    print("\n[4] SKU breakdown across all returned entitlements:")
    sku_counts: dict[str, int] = {}
    for e in ents:
        sku = str(e.get("sku_id") or "")
        sku_counts[sku] = sku_counts.get(sku, 0) + 1
    for sku, c in sorted(sku_counts.items(), key=lambda x: -x[1]):
        print(f"    {sku}: {c}")

    print("\n[5] Recommendation:")
    if not target_ents:
        print("    Discord is NOT returning the target guild's entitlement.")
        print("    Either Discord's API is degraded right now, OR the entitlement no longer exists.")
        print("    Re-run this script in a few minutes to see if results change.")
    else:
        print("    Discord IS returning the target guild's entitlement.")
        print("    The bot's cache must be stale or wholesale-replaced by an empty result.")
        print("    Force a refresh: restart bot OR call refresh_entitled_guilds(force=True).")


if __name__ == "__main__":
    asyncio.run(main())
