#!/usr/bin/env python3
"""2026-10-08: retry 503-failed handles (@c_valenzuelab, @azed_ai), merge into the
scan JSON, then run the dormancy check on every zero-qualifying handle."""
import os, json, time
import requests
from datetime import datetime, timezone, timedelta
from collections import Counter

DATE = "2026-10-08"
RAW = "/home/kiro/trend-engine/trends/x/raw"
JSON = f"{RAW}/scan_results_{DATE}_FULL.json"

env_path = os.path.expanduser("~/.hermes/.env")
API_KEY = None
with open(env_path) as f:
    for line in f:
        if line.startswith("GETXAPI_KEY="):
            API_KEY = line.strip().split("=", 1)[1]
            break
assert API_KEY, "no GETXAPI_KEY"

d = json.load(open(JSON))


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


def score(t):
    return ((t.get("likeCount") or 0) + 2 * (t.get("retweetCount") or 0)
            + 3 * (t.get("replyCount") or 0) + (t.get("viewCount") or 0) / 100)


def qualifies(t):
    return ((t.get("likeCount") or 0) >= 50 or (t.get("retweetCount") or 0) >= 10
            or (t.get("viewCount") or 0) >= 1000)


now = datetime.now(timezone.utc)
cutoff = now.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=3)
print(f"CUTOFF {cutoff.isoformat()}")

# --- retry failed handles ---
still_failed = []
for rec in d.get("failures", []):
    h = rec[0] if isinstance(rec, (list, tuple)) else str(rec).split(":")[0].strip().lstrip("@")
    ok = False
    for attempt in range(3):
        try:
            r = requests.get("https://api.getxapi.com/twitter/user/tweets",
                             headers={"Authorization": f"Bearer {API_KEY}"},
                             params={"userName": h, "count": 5}, timeout=60)
            if r.status_code == 200:
                tw = r.json().get("tweets", [])
                d.setdefault("raw", {})[h] = tw
                kept = 0
                for t in tw:
                    if t.get("retweeted_tweet") or t.get("type") == "retweet":
                        continue
                    if (t.get("text") or "").startswith("RT @"):
                        continue
                    dt = pdate(t.get("createdAt", ""))
                    if not dt or dt < cutoff or not qualifies(t):
                        continue
                    kept += 1
                    d["qualifying"].append({
                        "handle": h, "score": score(t),
                        "date": dt.strftime("%Y-%m-%d %H:%M UTC"),
                        "likes": t.get("likeCount") or 0,
                        "rt": t.get("retweetCount") or 0,
                        "replies": t.get("replyCount") or 0,
                        "views": t.get("viewCount") or 0,
                        "text": (t.get("text") or "").replace("\n", " ").strip(),
                        "url": f"https://x.com/{h}/status/{t.get('id')}",
                    })
                print(f"RETRY @{h}: fetched {len(tw)} tweets, {kept} qualifying")
                ok = True
                break
            else:
                print(f"RETRY @{h}: HTTP {r.status_code} attempt {attempt+1}")
        except Exception as e:
            print(f"RETRY @{h}: error {e} attempt {attempt+1}")
        time.sleep(3 * (attempt + 1))
    if not ok:
        still_failed.append([h, "retry failed"])

d["failures"] = still_failed
d["qualifying"].sort(key=lambda x: -x["score"])
json.dump(d, open(JSON, "w"))
print(f"MERGED -> {len(d['qualifying'])} qualifying, {len(still_failed)} still failing")

# --- dormancy check on zero-qualifying handles ---
c = Counter(x["handle"] for x in d["qualifying"])
zero = [h for h in d.get("handles", []) if h not in c]
print("\n===== DORMANCY CHECK (newest fetched tweet per zero-qualifying handle) =====")
for h in zero:
    raw = d.get("raw", {}).get(h) or []
    ds = [pdate(t.get("createdAt", "")) for t in raw]
    ds = [x for x in ds if x]
    if not ds:
        print(f"@{h}: NO TWEETS FETCHED (empty account / API returned nothing)")
        continue
    newest = max(ds)
    age = (now - newest).days
    verdict = "IN-WINDOW (genuine threshold artefact)" if newest >= cutoff else "DORMANT (threshold useless)"
    print(f"@{h}: newest {newest.strftime('%Y-%m-%d')} ({age}d) -> {verdict}")
