#!/usr/bin/env python3
"""Deep analysis for 2026-11-06 x-account-monitor run.

Buckets assigned by HANDLE GROUP first (never AI-filtered inside the loop),
disjoint-sum verified. Prints raw + organic core rankings with like rates,
24h deltas vs 11-05, per-handle freshness, originals-only dormancy,
offer/pricing grep over in-window originals, and unclassified-handle checks.
"""
import json, os, re
from datetime import datetime, timedelta, timezone

RAW = "/home/kiro/trend-engine/trends/x/raw"
D = "2026-11-06"
P = "2026-11-05"

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","Soaima_Ai","different_ai","via_ai_",
 "Teamily_AI","AIsaOneHQ","AiWithTariq","numerai","AidenChaoyangHe"}
NON_CORE = {"interesting_aIl","hubermanlab","NVIDIAAI"}
FILM = {"DiscussingFilm","nofilmschool"}
CORE = ["runwayml","CuriousRefuge","nofilmschool","venturetwins","Kling_ai","paultrillo",
 "c_valenzuelab","karenxcheng","higgsfield","pika_labs","EHuanglu","azed_ai","JeffSynthesized",
 "ai_filmmaker","Magiermogul","WuxiaRocks","JiamingSuen","higgsfield_ai","Chandan_Perla",
 "CharaspowerAI","AIWarper","ItsMaryamAi","ElsaSofia__AI","AI__TSUBAKI","heyglif", "openart_ai"]
CORESET = set(CORE)

STRONG = re.compile(r"\b(AI|A\.I\.|artificial intelligence|generative|text-to-video|image-to-video|"
                    r"Seedance|Midjourney|Sora|Veo|Kling|Runway|Pika|Higgsfield|ComfyUI|diffusion|"
                    r"machine learning|prompt|ChatGPT|GPT|LLM|agentic|model)\b", re.I)

def load(date):
    return json.load(open(os.path.join(RAW, f"scan_results_{date}_FULL.json")))

def pdate(s):
    try: return datetime.strptime(s, "%a %b %d %H:%M:%S %z %Y")
    except Exception: return None

def score(q):
    return q["likes"] + 2*q["rt"] + 3*q["replies"] + q["views"]/100

def likerate(q):
    return (q["likes"]/q["views"]*100) if q["views"] else 0.0

def tid(url):
    m = re.search(r"/status/(\d+)", url or "")
    return m.group(1) if m else None

cur = load(D); prev = load(P)
q = cur["qualifying"]
now = datetime.now(timezone.utc)

print(f"=== RUN {D} ===  handles={len(cur['handles'])} fetched={len(cur['raw'])} "
      f"failures={len(cur['failures'])} qualifying={len(q)}")
print(f"failures detail: {cur['failures']}")
print(f"prev {P}: qualifying={len(prev['qualifying'])} -> delta {len(q)-len(prev['qualifying']):+d}")

# ---- watchlist diff ----
wl_txt = open("/home/kiro/trend-engine/trends/x/raw/rising-accounts.md").read()
wl = sorted({h for h in re.findall(r"@(\w+)", wl_txt)})
print(f"watchlist md handles={len(wl)}  scan handles={len(cur['handles'])}")

# ---- disjoint buckets by handle group ----
buckets = {"core":[], "film":[], "irrelevant":[], "labs":[], "offtopic":[], "health":[]}
for x in q:
    h = x["handle"]
    if h == "NVIDIAAI" or h in ("OpenAI","AnthropicAI"): buckets["labs"].append(x)
    elif h == "interesting_aIl": buckets["offtopic"].append(x)
    elif h == "hubermanlab": buckets["health"].append(x)
    elif h in FILM: buckets["film"].append(x)
    elif h in IRRELEVANT: buckets["irrelevant"].append(x)
    else: buckets["core"].append(x)

tot = sum(len(v) for v in buckets.values())
print("\n=== BUCKETS ===")
for k,v in buckets.items():
    print(f"  {k:11s} {len(v):4d}")
print(f"  {'ASSIGNED':11s} {tot:4d}  vs qualifying {len(q)}  -> "
      f"{'OK' if tot==len(q) else 'MISMATCH'}")

film_ai = [x for x in buckets["film"] if STRONG.search(x["text"])]
irr_ai  = [x for x in buckets["irrelevant"] if STRONG.search(x["text"])]
print(f"  film AI-relevant: {len(film_ai)} of {len(buckets['film'])}")
print(f"  irrelevant AI-relevant: {len(irr_ai)} of {len(buckets['irrelevant'])}")

# ---- core rankings ----
core = sorted(buckets["core"], key=score, reverse=True)
print(f"\n=== CORE TOP 20 (raw score) of {len(core)} ===")
for i,x in enumerate(core[:20],1):
    print(f"{i:2d}|@{x['handle']:16s}|{x['likes']:6d}L|{x['rt']:5d}RT|{x['replies']:4d}R|"
          f"{x['views']:9d}V|{likerate(x):5.2f}%|{x['date']}|{x['url']}")
cut10 = score(core[9]) if len(core)>=10 else 0
cut11 = score(core[10]) if len(core)>10 else 0
print(f"raw core top-10 cutoff: {cut10:.0f} / rank 11: {cut11:.0f}")

org = [x for x in core if likerate(x) >= 0.15]
org.sort(key=score, reverse=True)
print(f"\n=== CORE TOP 12 ORGANIC (like rate >= 0.15%) of {len(org)} ===")
for i,x in enumerate(org[:12],1):
    print(f"{i:2d}|@{x['handle']:16s}|{x['likes']:6d}L|{x['views']:9d}V|{likerate(x):5.2f}%|"
          f"{x['date']}|{x['url']}")
paid = [x for x in core if likerate(x) < 0.15 and x["views"] >= 100000]
print(f"paid-reach core posts (>=100k views, <0.15% like rate): {len(paid)}")
for x in paid:
    print(f"   @{x['handle']} {x['likes']}L/{x['views']}V {likerate(x):.3f}% {x['date']}")

# ---- 24h deltas ----
prevm = {}
for x in prev["qualifying"]:
    i = tid(x["url"])
    if i: prevm[i] = x
print("\n=== 24H DELTAS (core, present both days) ===")
rows=[]
for x in core:
    i=tid(x["url"]); p=prevm.get(i)
    if not p: continue
    rows.append((x["likes"]-p["likes"], x["views"]-p["views"], x))
rows.sort(key=lambda r: r[0], reverse=True)
for dl,dv,x in rows[:14]:
    print(f"  +{dl:5d}L +{dv:8d}V  @{x['handle']:15s} now {x['likes']}L/{x['views']}V "
          f"{likerate(x):.2f}%  {x['date']}")
print("  --- negative / flat ---")
for dl,dv,x in rows:
    if dl<=5:
        print(f"  {dl:+6d}L {dv:+9d}V  @{x['handle']:15s} now {x['likes']}L/{x['views']}V "
              f"{likerate(x):.3f}%")

# ---- freshness ----
print("\n=== FRESHNESS (hours since newest fetched tweet) ===")
fr=[]
for h,tw in cur["raw"].items():
    ds=[pdate(t.get("createdAt","")) for t in tw]
    ds=[d for d in ds if d]
    if ds: fr.append(((now-max(ds)).total_seconds()/3600, h, len(ds)))
fr.sort()
print("  freshest:", ", ".join(f"@{h} {a:.1f}h" for a,h,n in fr[:12]))
print("  stalest: ", ", ".join(f"@{h} {a:.0f}h" for a,h,n in fr[-12:]))
print("  key accounts:")
for a,h,n in fr:
    if h in {"higgsfield","higgsfield_ai","runwayml","Kling_ai","pika_labs","EHuanglu","Flovaai",
             "azed_ai","CharaspowerAI","heyglif","c_valenzuelab","venturetwins","openart_ai",
             "AIWarper","ItsMaryamAi","ElsaSofia__AI","NVIDIAAI","CuriousRefuge","GoogleAI"}:
        print(f"    @{h:16s} n={n:2d} newest {a:6.1f}h ago")

# ---- dormancy: originals only, in-window ----
cutoff = now.replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(days=3)
print("\n=== DORMANCY (originals only) ===")
for h in ["CuriousRefuge","karenxcheng","higgsfield","higgsfield_ai","WuxiaRocks","AI__TSUBAKI",
          "EinsiaAI","azed_ai","ItsMaryamAi","openart_ai","AIWarper","ElsaSofia__AI"]:
    tw = cur["raw"].get(h) or []
    orig=[(pdate(t.get("createdAt","")),t) for t in tw
          if not t.get("retweeted_tweet") and t.get("type")!="retweet"
          and not (t.get("text") or "").startswith("RT @")]
    orig=[(d,t) for d,t in orig if d]
    if not orig:
        print(f"  @{h:16s} NO ORIGINALS IN FETCHED SET"); continue
    newest=max(d for d,_ in orig)
    inw=[t for d,t in orig if d>=cutoff]
    best=max((t.get('likeCount') or 0) for t in inw) if inw else 0
    print(f"  @{h:16s} newest {(now-newest).total_seconds()/3600:8.1f}h  originals={len(orig):2d}"
          f"  in-window={len(inw):2d}  best_likes={best:5d}"
          f"{'  <-- DORMANT' if newest<cutoff else ''}")

# ---- offer / pricing grep over in-window originals ----
PATS = [r"\bfree\b", r"giveaway", r"contest", r"competition", r"\bcredit", r"\bpromo\b",
        r"code\s+[A-Z0-9]{4,}", r"discount", r"\boff\b", r"%\s*off", r"\$mod", r"\$\d", r"\d+\s*/\s*sec",
        r"per second", r"unlimited", r"new users", r"expires", r"ends\b", r"until\b", r"deadline",
        r"apply by", r"\bprize", r"launch special", r"\btrial\b", r"open weights",
        r"open source", r"waitlist", r"early access", r"beta\b", r"award", r"\bwin\b", r"winner",
        r"now available", r"fully available", r"is live", r"\blive\b"]
rx = re.compile("|".join(PATS), re.I)
print("\n=== OFFER / PRICING GREP (in-window originals) ===")
n_orig=0
for h,tw in cur["raw"].items():
    for t in tw:
        if t.get("retweeted_tweet") or t.get("type")=="retweet": continue
        txt=(t.get("text") or "")
        if txt.startswith("RT @"): continue
        d=pdate(t.get("createdAt",""))
        if not d or d<cutoff: continue
        n_orig+=1
        if rx.search(txt):
            hits=set(m.group(0).lower() for m in rx.finditer(txt))
            print(f"  @{h:15s} {(t.get('likeCount') or 0):5d}L/{(t.get('viewCount') or 0):8d}V "
                  f"{d.strftime('%m-%d %H:%M')} {sorted(hits)[:5]}")
            print(f"      {txt.replace(chr(10),' ')[:260]}")
print(f"  ({n_orig} in-window originals scanned)")

# ---- unclassified handles in top ranks ----
print("\n=== UNCLASSIFIED HANDLE CHECK ===")
known = CORESET | IRRELEVANT | NON_CORE | FILM
seen=set()
for i,x in enumerate(core[:25],1):
    if x["handle"] not in known and x["handle"] not in seen:
        seen.add(x["handle"])
        print(f"  core #{i} @{x['handle']} NOT in any set: {x['likes']}L/{x['views']}V "
              f"{likerate(x):.2f}% {x['url']}")
        print(f"      {x['text'][:220]}")

# ---- spotlights ----
print("\n=== FILM BUCKET (AI matches) ===")
for x in sorted(film_ai, key=score, reverse=True):
    print(f"  @{x['handle']} {x['likes']}L/{x['views']}V {x['date']}: {x['text'][:200]}")
print("  (empty = correct output)")

print("\n=== FILM BUCKET top 5 raw (correctly excluded) ===")
for x in sorted(buckets["film"], key=score, reverse=True)[:5]:
    print(f"  @{x['handle']} {x['likes']}L/{x['views']}V {x['date']}: {x['text'][:120]}")

print("\n=== IRRELEVANT AI-RELEVANT ===")
for x in sorted(irr_ai, key=score, reverse=True)[:12]:
    print(f"  @{x['handle']} {x['likes']}L/{x['views']}V {likerate(x):.2f}% {x['date']}: {x['text'][:150]}")

print("\n=== LABS ===")
for x in sorted(buckets["labs"], key=score, reverse=True)[:12]:
    print(f"  @{x['handle']} {x['likes']}L/{x['views']}V {x['date']}: {x['text'][:150]}")
