#!/usr/bin/env python3
"""verify_hc39.py — verifikasi INDEPENDEN hasil create hc39 (fetch ulang per-ID dari API)."""
import json, os, re, subprocess, sys

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
sys.path.insert(0, WS)
from repliz_client import ReplizClient, ACC

IDS = {
    "threads": "6aac3a009aa606c3bd9cd2e7",
    "linkedin": "6aac3a00fc107e4fe5d5a012",
    "facebook": "6aac3a00fc107e4fe5d5a024",
}
EXPECT_MEDIA = ["ss_hc39_iklanfb_01_cover.jpg", "ss_hc39_iklanfb_02_tidakboleh.jpg",
                "ss_hc39_iklanfb_03_boleh.jpg", "ss_hc39_iklanfb_04_targeting.jpg",
                "ss_hc39_iklanfb_05_cta.jpg"]
CTA_RE = re.compile(r"komentar|pendapat|diskusi|setuju|share|pengalaman|menurut|bagaimana|apa yang", re.I)
INGRESS = ["103.84.155.153", "103.84.155.217"]
fails = []

c = ReplizClient()


def doc_of(sid):
    d = c.get("/public/schedule/%s" % sid)
    return d.get("doc") or d.get("data") or d


def check(cond, msg):
    print(("  \u2705 " if cond else "  \u274c ") + msg)
    if not cond:
        fails.append(msg)


def caption_rules(name, txt, limit=None):
    check(txt is not None and len(txt) > 0, "%s caption ada" % name)
    if limit:
        check(len(txt) <= limit, "%s caption %d char <= %d" % (name, len(txt), limit))
    check(not re.findall(r"@\w+", txt), "%s 0 mention" % name)
    caps = [t for t in re.findall(r"#(\w+)", txt) if t != t.lower()]
    check(not caps, "%s hashtag huruf kecil semua" % name)
    check(CTA_RE.search(txt[-200:]) is not None, "%s ada pancingan diskusi di ekor" % name)
    check("..." not in txt, "%s tidak ada elipsis" % name)


print("=== 1) THREADS album ===")
t = doc_of(IDS["threads"])
check(t.get("accountId") == ACC.STUDIOSOFT_THREADS, "accountId = SS Threads")
check(t.get("type") == "album", "type=album")
check(t.get("status") == "pending", "status=pending (%s)" % t.get("status"))
check(t.get("scheduleAt") == "2026-09-18T02:00:00.000Z", "scheduleAt=%s (18 Sep 09:00 WIB)" % t.get("scheduleAt"))
mnames = [os.path.basename((m.get("url") or "").split("?")[0]) for m in (t.get("medias") or [])]
check(mnames == EXPECT_MEDIA, "5 media urut 01-05: %s" % mnames)
check(len(t.get("replies") or []) == 0, "album replies kosong (replies dipasang di post teks)")
caption_rules("Threads", t.get("description") or "", limit=500)
check("https://studiosoft.id/iklan-facebook-rumah-sakit/" in (t.get("description") or ""),
      "link artikel Threads ada")

print("=== 2) THREADS 2 replies (terpasang ke album) ===")
rows, page = [], 1
while True:
    d = c.get("/public/schedule?page=%d&limit=100" % page)
    rows.extend(d.get("docs", []))
    if page >= (d.get("totalPages") or 1):
        break
    page += 1
rep = []


def _norm_reply(x):
    """Repliz kadang balikin ObjectId sebagai dict char-index: {'0':'6','1':'a',...}."""
    if isinstance(x, dict):
        keys = [k for k in x if k.isdigit()]
        return "".join(str(x[k]) for k in sorted(keys, key=int))
    return str(x)


for r in rows:
    if r.get("accountId") != ACC.STUDIOSOFT_THREADS:
        continue
    reps = [_norm_reply(x) for x in (r.get("replies") or [])]
    if IDS["threads"] in reps and (r.get("scheduleAt") or "").startswith("2026-09-18T02:0") \
            and r.get("_id") != IDS["threads"]:
        rep.append(r)
check(len(rep) == 2, "2 reply menunjuk ke album (%d)" % len(rep))
for r in sorted(rep, key=lambda x: x.get("scheduleAt")):
    print("     %s | %s | %s" % (r.get("scheduleAt"), r.get("status"), (r.get("description") or "").split("\n")[0][:60]))

print("=== 3) LINKEDIN (TEXT-only) ===")
l = doc_of(IDS["linkedin"])
check(l.get("accountId") == ACC.STUDIOSOFT_LINKEDIN, "accountId = SS LinkedIn")
check(l.get("type") == "text", "type=text")
check(len(l.get("medias") or []) == 0, "medias=0 (tanpa gambar)")
check(len(l.get("replies") or []) == 0, "replies=0")
check(l.get("status") == "pending", "status=pending")
check(l.get("scheduleAt") == "2026-10-09T16:00:00.000Z", "scheduleAt=%s (9 Okt 23:00 WIB)" % l.get("scheduleAt"))
check("https://studiosoft.id/klinik-kecil-butuh-digital-marketing/" in (l.get("description") or ""),
      "link artikel LinkedIn ada")
caption_rules("LinkedIn", l.get("description") or "")

print("=== 4) FACEBOOK (TEXT-only, TANPA media) ===")
f = doc_of(IDS["facebook"])
check(f.get("accountId") == ACC.STUDIOSOFT_FB, "accountId = SS FB")
check(f.get("type") == "text", "type=text")
check(len(f.get("medias") or []) == 0, "medias=0 (tanpa gambar/carousel)")
check(len(f.get("replies") or []) == 0, "replies=[] WAJIB")
check(f.get("status") == "pending", "status=pending")
check(f.get("scheduleAt") == "2026-09-18T12:30:00.000Z", "scheduleAt=%s (18 Sep 19:30 WIB)" % f.get("scheduleAt"))
check("https://studiosoft.id/panduan-seo-klinik-rumah-sakit/" in (f.get("description") or ""),
      "link artikel FB ada")
caption_rules("Facebook", f.get("description") or "")

print("=== 5) IG SS tidak disentuh (0 media hc39) ===")
ig = [r for r in rows if r.get("accountId") == ACC.STUDIOSOFT_IG
      and any("ss_hc39" in (m.get("url") or "") for m in (r.get("medias") or []))]
check(not ig, "tidak ada media hc39 di IG SS")
fb_media = [r for r in rows if r.get("accountId") == ACC.STUDIOSOFT_FB
            and any("ss_hc39" in (m.get("url") or "") for m in (r.get("medias") or []))]
check(not fb_media, "tidak ada media hc39 di FB SS")
li_media = [r for r in rows if r.get("accountId") == ACC.STUDIOSOFT_LINKEDIN
            and any("ss_hc39" in (m.get("url") or "") for m in (r.get("medias") or []))]
check(not li_media, "tidak ada media hc39 di LinkedIn SS")

print("=== 6) media masih 200 di KEDUA ingress (cek ulang) ===")
for f_ in EXPECT_MEDIA:
    u = "https://mantapserver.tail3947bb.ts.net/openclaw-img/" + f_
    codes = []
    for ip in INGRESS:
        r = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "30",
                            "--resolve", "mantapserver.tail3947bb.ts.net:443:%s" % ip, u],
                           capture_output=True, text=True)
        codes.append(r.stdout.strip())
    check(codes == ["200", "200"], "%s -> %s" % (f_, codes))

print("\n" + "=" * 55)
print("SEMUA VERIFIKASI LULUS" if not fails else "GAGAL %d: %s" % (len(fails), fails))
sys.exit(0 if not fails else 1)
