#!/usr/bin/env python3
"""rank.py: rank every fetched post by COMMENTS (the signal for comment-to-DM posts), not likes,
and spot the "comment KEYWORD" call to action in the caption.

Usage:
  python3 rank.py                 # top 40 from the last 120 days
  python3 rank.py --top 20 --days 60
Input:  raw/*.json  (from fetch.py)
Output: ranked.json (every post) + ranked.md (the top N as a table you can hand to your AI)
Only uses the Python standard library.
"""
import argparse, datetime, glob, json, re, sys

# catches: comment "WORD", comment WORD, comment the word WORD, comment below WORD
CTA = re.compile(r'\bcomment\s*(?:the\s+word\s+|below\s+)?["“”\'‘’]?([A-Z0-9][A-Za-z0-9\-]{1,20})["“”\'‘’]?', re.I)


def keyword(caption):
    mm = CTA.search(caption or "")
    if not mm:
        return None
    w = mm.group(1)
    # only count it as a keyword CTA if it's ALL CAPS or quoted ("comment below" alone isn't one)
    return w.upper() if (w.isupper() or re.search(r'["“”\'‘’]', mm.group(0))) else None


def main():
    ap = argparse.ArgumentParser(description="Rank fetched posts by comments.")
    ap.add_argument("--top", type=int, default=40, help="how many rows in ranked.md (default 40)")
    ap.add_argument("--days", type=int, default=120, help="only posts from the last N days (default 120)")
    ap.add_argument("--raw", default="raw", help="folder with fetch.py output (default raw/)")
    a = ap.parse_args()

    files = glob.glob(f"{a.raw}/*.json")
    if not files:
        sys.exit(f"No files in {a.raw}/. Run fetch.py first.")
    since = (datetime.date.today() - datetime.timedelta(days=a.days)).isoformat()
    rows, skipped = [], []
    for f in files:
        d = json.load(open(f, encoding="utf-8"))
        if d.get("error"):
            skipped.append(d.get("handle", f))
            continue
        fol = d.get("followers_count") or 0
        for m in d.get("media", []):
            ts = (m.get("timestamp") or "")[:10]
            if not ts or ts < since:
                continue
            cap = m.get("caption") or ""
            c = m.get("comments_count") or 0
            rows.append(dict(handle=d.get("handle"), followers=fol, comments=c, likes=m.get("like_count"),
                             per_1k_followers=round(1000 * c / fol, 1) if fol else None,
                             date=ts, format=m.get("media_product_type") or m.get("media_type") or "",
                             keyword=keyword(cap), url=m.get("permalink", ""),
                             hook=(cap.strip().split("\n")[0] if cap.strip() else "")[:140]))

    rows.sort(key=lambda r: -r["comments"])
    json.dump(rows, open("ranked.json", "w", encoding="utf-8"), indent=1)
    with open("ranked.md", "w", encoding="utf-8") as f:
        f.write(f"# Top {a.top} posts by comments (last {a.days} days)\n\n")
        f.write("| # | Creator | Comments | Likes | Comments/1k followers | Date | Format | Keyword | URL | Caption hook |\n")
        f.write("|---|---|---|---|---|---|---|---|---|---|\n")
        for i, r in enumerate(rows[:a.top], 1):
            likes = f"{r['likes']:,}" if isinstance(r["likes"], int) else "hidden"
            per = r["per_1k_followers"] if r["per_1k_followers"] is not None else ""
            f.write(f"| {i} | @{r['handle']} | {r['comments']:,} | {likes} | {per} | {r['date']} | {r['format']} | "
                    f"{r['keyword'] or ''} | {r['url']} | {r['hook'].replace('|', '/')} |\n")
    kw = sum(1 for r in rows[:a.top] if r["keyword"])
    print(f"{len(rows)} posts ranked → ranked.md (top {a.top}, {kw} with a comment-KEYWORD CTA)")
    if skipped:
        print("skipped (fetch errors): " + ", ".join(skipped))


if __name__ == "__main__":
    main()
