#!/usr/bin/env python3
"""X monitor deep audit 2026-10-29: corrected buckets, top verification, freshness, dormancy, new handles."""
import json, re, os
from datetime import datetime, timezone, timedelta

RAW = "/home/kiro/trend-engine/trends/x/raw"
D = json.load(open(f"{RAW}/scan_results_2026-10-29_FULL.json"))
Y = json.load(open(f"{RAW}/scan_results_2026-10-28_FULL.json"))

IRRELEVANT = {
    "AIBuzzNews","AIGuideHQ","AITECHio","AIFrontliner","TheAIColony","AITOPIAai","GoogleLabs",
    "GoogleAI","DonutAI","cladlabs","FaithJaiye2187","KammelaBala","MyStageAI","AlexStudio44",
    "AI_with_jasmin","Ai_Vaidehi","ChrisLaubAI","CINEMA505","OpenAI","AnthropicAI","AIScottAdams",
    "AISuperDomain","AI_Jasonyu","AIByLeo",
}
FILM_INDUSTRY = {"DiscussingFilm","nofilmschool"}
LABS = {"OpenAI","AnthropicAI","NVIDIAAI"}
OFFTOPIC = {"interesting_aIl","hubermanlab"}

cutoff = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=3)
q = D["qualifying"]
raw = D["raw"]

def parse_d(s):
    return datetime.strptime(s, "%a %b %d %H:%M:%S %z %Y")

print(f"CUTOFF {cutoff.isoformat()}   qualifying {len(q)}   handles {len(D['handles'])}   failures {D['failures']}")

# ---- bucket counts with explicit disjoint assignment (order matters) ----
def bucket(x):
    h = x["handle"]
    if h in LABS: return "labs"
    if h in OFFTOPIC: return "offtopic"
    if h in FILM_INDUSTRY: return "film"
    if h in IRRELEVANT: return "irrelevant"
    return "core"

from collections import Counter
bc = Counter(bucket(x) for x in q)
print("BUCKETS(disjoint)", dict(bc), "sum", sum(bc.values()))

core = [x for x in q if bucket(x)=="core"]
off  = [x for x in q if bucket(x)=="offtopic"]
film = [x for x in q if bucket(x)=="film"]
irr  = [x for x in q if bucket(x)=="irrelevant"]
labs = [x for x in q if bucket(x)=="labs"]

core.sort(key=lambda x: x["score"], reverse=True)
print("\n=== CORRECTED CORE TOP 20 ===")
for i, x in enumerate(core[:20], 1):
    print(f"{i}|@{x['handle']}|{x['likes']}L|{x['rt']}RT|{x['replies']}R|{x['views']}V|{x['date']}|{x['score']:.0f}|{x['text'][:140]}")
print("cutoff rank10", f"{core[9]['score']:.0f}", " rank11", f"{core[10]['score']:.0f}", f"@{core[10]['handle']}")

# ---- watchlist diff ----
added = sorted(set(D["handles"]) - set(Y["handles"]), key=str.lower)
removed = sorted(set(Y["handles"]) - set(D["handles"]), key=str.lower)
print(f"\nWATCHLIST {len(D['handles'])} (yesterday {len(Y['handles'])}) ADDED {added} REMOVED {removed}")

# ---- coverage ----
cov = sorted({x["handle"] for x in q}, key=str.lower)
print(f"COVERAGE {len(cov)} handles: " + ", ".join(cov))

# ---- verify top 12 against raw ----
print("\n=== TOP-12 RAW VERIFICATION ===")
for i, x in enumerate(core[:12], 1):
    tid = x["url"].rsplit("/",1)[-1]
    h = x["handle"]
    match = None
    for r in raw.get(h, []):
        if str(r.get("id")) == tid:
            match = r; break
    if not match:
        print(f"{i} @{h} NOT FOUND IN RAW {tid}"); continue
    media = match.get("media") or []
    mtype = media[0].get("type") if media else "none"
    lr = (x["likes"]/x["views"]*100) if x["views"] else 0
    print(f"{i} @{h} author={match.get('author',{}).get('userName')} media={mtype} "
          f"rt={bool(match.get('retweeted_tweet'))} quote={bool(match.get('quoted_tweet'))} "
          f"reply={bool(match.get('isReply'))} like_rate={lr:.2f}% | {x['url']}")

# ---- new handle profiling (AI-term density, cadence, media mix) ----
AI_TERMS = re.compile(r"\b(ai|a\.i\.|seedance|kling|runway|sora|veo|midjourney|higgsfield|nano.?banana|"
                      r"llm|gpt|claude|gemini|diffusion|generative|prompt|text.to.video|image.to.video|"
                      r"flux|ideogram|magnific|pika|hailuo|minimax|wan)\b", re.I)
print("\n=== NEW HANDLE PROFILE ===")
for h in (added or ["(none)"]):
    if h not in raw:
        print(f"@{h}: NOT FETCHED (failure)"); continue
    tw = raw[h]
    orig = [t for t in tw if not t.get("retweeted_tweet") and not (t.get("text") or "").startswith("RT @")]
    inwin = [t for t in orig if parse_d(t["createdAt"]) >= cutoff]
    hits = sum(1 for t in inwin if AI_TERMS.search(t.get("text") or ""))
    medias = Counter((t.get("media") or [{}])[0].get("type","none") for t in inwin)
    likes = sorted([t.get("likeCount") or 0 for t in inwin], reverse=True)
    print(f"@{h}: fetched {len(tw)} orig {len(orig)} in-window-orig {len(inwin)} AI-term-hits {hits}/{len(inwin)} "
          f"media {dict(medias)} top-likes {likes[:5]}")

# ---- freshness per handle ----
print("\n=== FRESHNESS (hours since newest fetched tweet) ===")
now = datetime.now(timezone.utc)
fr = []
for h, tw in raw.items():
    ds = [parse_d(t["createdAt"]) for t in tw if t.get("createdAt")]
    if not ds: continue
    newest = max(ds); oldest = min(ds)
    fr.append((h, (now-newest).total_seconds()/3600, len(tw), newest,
               sum(1 for d in ds if d >= cutoff)))
fr.sort(key=lambda r: r[1])
print("FRESHEST:", ", ".join(f"@{h} {h2:.1f}h" for h,h2,_,_,_ in fr[:10]))
print("STALEST:", ", ".join(f"@{h} {h2:.1f}h" for h,h2,_,_,_ in fr[-12:]))
print("\nKEY ACCOUNTS:")
for h in ["Flovaai","higgsfield","higgsfield_ai","runwayml","venturetwins","Kling_ai","c_valenzuelab",
          "CharaspowerAI","AIWarper","ItsMaryamAi","Soaima_Ai","ElsaSofia__AI","NVIDIAAI","OpenAI","AnthropicAI",
          "EHuanglu","azing"]:
    for hh,hh2,n,newest,inw in fr:
        if hh == h:
            print(f"  @{h} n={n} newest {newest.strftime('%m-%d %H:%M')} ({hh2:.1f}h) in-window {inw}")

# ---- dormancy: originals only, per tier-2 + flagged ----
TIER2 = ["CuriousRefuge","paultrillo","JeffSynthesized","ai_filmmaker","Magiermogul","JiamingSuen","Chandan_Perla"]
print("\n=== DORMANCY (originals only) ===")
for h in TIER2 + ["karenxcheng","WuxiaRocks","Flovaai","pika_labs","numerai","via_ai_"]:
    tw = raw.get(h)
    if not tw:
        print(f"@{h}: NOT FETCHED"); continue
    orig = [t for t in tw if not t.get("retweeted_tweet") and not (t.get("text") or "").startswith("RT @")]
    if not orig:
        print(f"@{h}: 0 originals of {len(tw)} fetched -> RT-ONLY"); continue
    newest = max(parse_d(t["createdAt"]) for t in orig)
    inw = [t for t in orig if parse_d(t["createdAt"]) >= cutoff]
    best = max((t.get("likeCount") or 0) for t in inw) if inw else 0
    verdict = "DORMANT" if not inw else ("thresh-artefact" if best < 50 else "qualifying")
    print(f"@{h}: orig {len(orig)}/{len(tw)} newest {newest.strftime('%Y-%m-%d %H:%M')} "
          f"({(now-newest).total_seconds()/3600:.1f}h) in-window-orig {len(inw)} best-likes {best} -> {verdict}")

# ---- tier2 qualifying / silent ----
print("\n=== TIER-2 ===")
for h in TIER2:
    hits = [x for x in q if x["handle"]==h]
    print(f"@{h}: {len(hits)} qualifying")
