"""Orchestrate a full backfill for every pubkey the given user follows.

Flow (relay-outer, follow-inner):
  1. Fetch the user's latest kind-3 contact list via REQ and ingest it.
  2. Read the follow list out of storage (tags on the newest kind-3 event).
  3. For each relay open a WS and send one REQ per follow serially on it,
     each with its own per-(follow, relay) since — no wasted re-fetches
     caused by the least-synced author.
  4. Compute per-follow deltas in one storage query from before/after counts.
  5. Lazy-load users.json for human-readable names.

Output is intentionally compact: per-follow deltas only, no per-relay
breakdown (relay status lives on the relays/Relay rows, queryable
directly when diagnosing). Pubkeys truncated to 6 hex chars.

Driven by `daemon.follows_of()` / `daemon.events_count_per_pubkey()` on
`IngestDaemonSQL`.
"""

import json
from pathlib import Path as FsPath

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ingest_sql import IngestDaemonSQL

USERS_JSON = FsPath(__file__).parent.parent.parent / "users.json"
SHORT = 6


def run(daemon: "IngestDaemonSQL", user_hex: str, limit_per_follow: int = 500) -> dict:
    daemon.req_and_ingest({"authors": [user_hex], "kinds": [3], "limit": 1})

    follows = daemon.follows_of(user_hex)
    if not follows:
        return {
            "user": user_hex[:SHORT],
            "follows_count": 0,
            "total_new_events": 0,
            "per_follow": [],
        }

    before = daemon.events_count_per_pubkey(follows)
    daemon.update_graph_with_events_authored_by_each(
        follows, limit=limit_per_follow, full=False,
    )
    after = daemon.events_count_per_pubkey(follows)

    names = _load_users_json()
    per_follow: list[dict] = []
    total_new = 0
    for pk in follows:
        new = after.get(pk, 0) - before.get(pk, 0)
        total_new += new
        per_follow.append({
            "pubkey": pk[:SHORT],
            "name": (names.get(pk) or {}).get("name"),
            "new_events": new,
            "total_events": after.get(pk, 0),
        })
    per_follow.sort(key=lambda r: r["new_events"], reverse=True)

    return {
        "user": user_hex[:SHORT],
        "follows_count": len(follows),
        "total_new_events": total_new,
        "per_follow": per_follow,
    }


def _load_users_json() -> dict:
    try:
        with open(USERS_JSON) as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return {}
