#!/usr/bin/env python3
"""X account monitor deep pass 2026-11-03: disjoint buckets, organic core top10,
watchlist diff, freshness, originals-only dormancy, film STRONG_TERMS audit."""
import json, re
from datetime import datetime, timezone, timedelta
from collections import Counter

D = "/home/kiro/trend-engine/trends/x/raw/"
d = json.load(open(D + "scan_results_2026-11-03_FULL.json"))
y = json.load(open(D + "scan_results_2026-11-02_FULL.json"))
q = d["qualifying"]

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

AI_TERMS = re.compile(r"\b(ai\b|a\.i\.|seedance|kling|runway|veo|sora|minimax|hailuo|higgsfield|"
  r"midjourney|nano ?banana|gpt-?[0-9.]*|chatgpt|gemini|generative|render|vfx|ai film|aifilm|"
  r"grokbot|motion capture|deepfake|davinci|blender|autocad|storyboard|(ai|3d|generated) ?animation|"
  r"diffusion|comfyui|(?<!\bfilm )(?<!\bfilm-)(?<!\bscreenplay )(?<!\bscreenplay-)\bprompt)", re.I)
STRONG = re.compile(r"\b(a\.i\.|seedance|kling|runway|veo|sora|minimax|hailuo|higgsfield|midjourney|"
  r"nano ?banana|chatgpt|gemini|generative|vfx|ai film|aifilm|deepfake|comfyui|diffusion|"
  r"(ai|3d|generated) ?animation)\b", re.I)

def rate(x):
    v = x["views"] or 0
    return (x["likes"]/v*100) if v else 0.0

buckets = {"core":[], "offtopic":[], "health":[], "film":[], "irrelevant":[], "labs":[], "new":[]}
for x in q:
    h = x["handle"]
    x["is_ai"] = bool((STRONG if h in FILM else AI_TERMS).search(x["text"]))
    if h in FILM: buckets["film"].append(x)
    elif h in LABS: buckets["labs"].append(x)
    elif h in IRRELEVANT: buckets["irrelevant"].append(x)
    elif h in NEW: buckets["new"].append(x)
    elif h in OFFTOPIC: buckets["offtopic"].append(x)
    elif h in HEALTH: buckets["health"].append(x)
    else: buckets["core"].append(x)

print("="*70)
print("DISJOINT BUCKETS  total qualifying", len(q))
tot=0
for k,v in buckets.items():
    ai=sum(1 for x in v if x["is_ai"]) if k in ("film","irrelevant") else None
    extra=f"  (AI-relevant {ai})" if ai is not None else ""
    print(f"  {k:12s} {len(v):4d}{extra}")
    tot+=len(v)
print("  SUM", tot, "== qualifying", len(q), "OK" if tot==len(q) else "MISMATCH")

print("\n"+"="*70)
print("RAW core ranking (top 12) -- ALL handles, engagement only")
for i,x in enumerate(sorted(buckets["core"],key=lambda z:z["score"],reverse=True)[:12],1):
    print(f"{i:2d}|@{x['handle']:16s}|{x['likes']:6d}L|{x['rt']:5d}RT|{x['views']:9d}V|score {x['score']:8.0f}|like% {rate(x):5.2f}|{x['date']}")

print("\n"+"="*70)
print("ORGANIC core top 12 (like rate >= 0.15%)")
organic = [x for x in buckets["core"] if rate(x) >= 0.15]
organic.sort(key=lambda z: z["score"], reverse=True)
for i,x in enumerate(organic[:12],1):
    print(f"{i:2d}|@{x['handle']:16s}|{x['likes']:6d}L|{x['rt']:5d}RT|{x['replies']:4d}R|{x['views']:9d}V|{x['score']:7.0f}|lk%{rate(x):5.2f}|{x['date']}")
    print(f"    {x['text'][:180]}")
    print(f"    {x['url']}")
print("\nORGANIC cutoff:", f"{organic[9]['score']:.0f}" if len(organic)>=10 else "n/a",
      "| rank11:", f"{organic[10]['score']:.0f}" if len(organic)>10 else "n/a")
print("RAW cutoff:", f"{sorted(buckets['core'],key=lambda z:z['score'],reverse=True)[9]['score']:.0f}",
      "| rank11:", f"{sorted(buckets['core'],key=lambda z:z['score'],reverse=True)[10]['score']:.0f}")

print("\n"+"="*70)
print("LOW LIKE-RATE (<0.15%) inside core -- paid/pushed reach")
for x in sorted([z for z in buckets["core"] if rate(z)<0.15],key=lambda z:z["score"],reverse=True):
    print(f"  @{x['handle']:16s}|{x['likes']:5d}L|{x['views']:9d}V|lk%{rate(x):6.3f}|{x['date']}|{x['text'][:90]}")

print("\n"+"="*70)
print("NEW / UNCLASSIFIED handles:")
for x in sorted(buckets["new"],key=lambda z:z["score"],reverse=True):
    print(f"  @{x['handle']}|{x['likes']}L|{x['rt']}RT|{x['views']}V|lk%{rate(x):.2f}|{x['date']}")
    print(f"    {x['text'][:300]}")
    print(f"    {x['url']}")

print("\n"+"="*70)
print("FILM-INDUSTRY bucket:", len(buckets["film"]), "total,", sum(1 for x in buckets["film"] if x["is_ai"]), "AI-relevant")
farm = Counter(x["handle"] for x in q if x["handle"] in FILM)
print("  counts:", dict(farm))
for h in FILM:
    posts=[t for t in d["raw"].get(h,[]) if not t.get("retweeted_tweet")]
    s=sum(1 for t in posts if STRONG.search(t.get("text") or ""))
    a=sum(1 for t in posts if re.search(r"\bai\b", (t.get("text") or ""), re.I))
    print(f"  @{h}: {len(posts)} originals fetched, STRONG hits={s}, bare-ai hits={a}")

print("\n"+"="*70)
print("HANDLE COVERAGE:", len(set(x['handle'] for x in q)), "of", len(d['handles']))
c = Counter(x["handle"] for x in q)
print("  ", ", ".join(f"@{h}({n})" for h,n in c.most_common()))

print("\n"+"="*70)
print("FRESHNESS (newest fetched tweet per handle, hours ago)")
cutoff = datetime(2026,10,31,0,0,0)
def pd(s):
    try: return datetime.strptime(s,"%a %b %d %H:%M:%S %z %Y").replace(tzinfo=None)
    except Exception: return None
now = datetime.utcnow()
rows=[]
for h,tw in d["raw"].items():
    dts=[pd(t.get("createdAt","")) for t in tw]
    dts=[x for x in dts if x]
    if not dts: continue
    mx=max(dts)
    origs=[t for t in tw if not t.get("retweeted_tweet") and not (t.get("text") or "").startswith("RT @")]
    inw=sum(1 for t in origs if (pd(t.get("createdAt","")) or datetime.min)>=cutoff)
    rows.append((h,(now-mx).total_seconds()/3600,len(tw),inw,mx))
rows.sort(key=lambda r:r[1])
print("  FRESH 8:", ", ".join(f"@{h} {a:.1f}h" for h,a,_,_,_ in rows[:8]))
print("  KEY ACCOUNTS:")
for h in ["NVIDIAAI","venturetwins","pika_labs","CharaspowerAI","c_valenzuelab","runwayml",
          "Kling_ai","AIWarper","higgsfield","Flovaai","higgsfield_ai","EHuanglu","azed_ai",
          "AIsaOneHQ","AiWithTariq","openart_ai","ElsaSofia__AI","ItsMaryamAi","WuxiaRocks","AI__TSUBAKI"]:
    for hh,a,n,i2,mx in rows:
        if hh==h: print(f"    @{h:15s} n={n:2d} newest {a:7.1f}h ({mx}) in-window originals={i2}")
print("  STALEST 12:", ", ".join(f"@{h} {a:.0f}h" for h,a,_,_,_ in rows[-12:]))
stale=[r for r in rows if r[1]>48]
print(f"  handles >48h stale: {len(stale)}")

print("\n"+"="*70)
print("DORMANCY (originals only, RT-filtered) -- zero-qualifying handles")
zero=[h for h in d["handles"] if h not in c]
for h in zero:
    origs=[t for t in d["raw"].get(h,[]) if not t.get("retweeted_tweet") and not (t.get("text") or "").startswith("RT @")]
    dts=[pd(t.get("createdAt","")) for t in origs]; dts=[x for x in dts if x]
    inw=[t for t in origs if (pd(t.get("createdAt","")) or datetime.min)>=cutoff]
    best=max([(t.get("likeCount") or 0) for t in inw], default=0)
    if not dts: print(f"  @{h}: NO DATA"); continue
    age=(datetime.utcnow()-max(dts)).total_seconds()/3600
    verdict="DORMANT" if not inw else f"THRESHOLD ARTEFACT (inwin={len(inw)}, best={best}L)"
    print(f"  @{h:18s} newest original {max(dts)} ({age:.1f}h)  {verdict}")

print("\n"+"="*70)
print("TREND (qualifying totals)")
for dt in ["2026-10-26","2026-10-27","2026-10-28","2026-10-29","2026-10-30","2026-10-31","2026-11-01","2026-11-02","2026-11-03"]:
    try:
        z=json.load(open(D+f"scan_results_{dt}_FULL.json"))
        print(f"  {dt}: {len(z['qualifying']):4d} qual / {len(z['handles'])} scanned")
    except Exception as e: print(f"  {dt}: {e}")

print("\n"+"="*70)
print("WATCHLIST DIFF vs yesterday")
print("  yesterday handles:", len(y["handles"]), " today:", len(d["handles"]))
print("  added:", sorted(set(d["handles"])-set(y["handles"])))
print("  removed:", sorted(set(y["handles"])-set(d["handles"])))
