#!/usr/bin/env python3
"""hc42 retry — HANYA Threads (album ss_hc42_seoklinik_* + 2 replies).

Run hc42 utama (21 Sep 2026): LinkedIn + FB sukses; album Threads gagal dgn
HTTP 500 "Cannot read properties of undefined (reading '0')" dari Repliz (server-side).
Script ini mengulang create album + replies SAJA, dengan retry, dan idempotency guard
(tidak create kalau media hc42 sudah ada di jadwal).
"""
import json, os, subprocess, sys, time
from datetime import datetime, timezone, timedelta

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

c = ReplizClient()
TITLE = "Panduan SEO untuk Klinik dan Rumah Sakit: Biar Mudah Ditemukan Pasien di Google"
ARTICLE_URL = "https://studiosoft.id/panduan-seo-klinik-rumah-sakit/"
HASHTAG_LINE = "#studiosoft #seoklinik #rumahsakit #klinik #kesehatan"
MEDIA_FILES = [
    "ss_hc42_seoklinik_01_cover.jpg",
    "ss_hc42_seoklinik_02_keyword.jpg",
    "ss_hc42_seoklinik_03_local.jpg",
    "ss_hc42_seoklinik_04_teknis.jpg",
    "ss_hc42_seoklinik_05_cta.jpg",
]
MEDIA_URLS = [IMG_BASE_URL.rstrip("/") + "/openclaw-img/" + f for f in MEDIA_FILES]
INGRESS = ["103.84.155.153", "103.84.155.217"]
THREADS_TXT = open("/tmp/hc42_threads_caption.txt").read() if os.path.exists("/tmp/hc42_threads_caption.txt") else None
REPLY1 = ("Baca selengkapnya: %s\n\nButuh partner SEO untuk RS atau klinik Anda?\n"
          "www.studiosoft.id" % ARTICLE_URL)
REPLY2 = HASHTAG_LINE


def get_retry(ep, tries=6):
    last = None
    for i in range(tries):
        try:
            return c.get(ep)
        except Exception as e:
            last = e
            time.sleep(3 + 3 * i)
    raise last


def all_docs():
    docs, page = [], 1
    while True:
        d = get_retry("/public/schedule?page=%d&limit=100" % page)
        docs.extend(d.get("docs", []))
        if page >= (d.get("totalPages") or 1):
            break
        page += 1
    return docs


def scan_media(statuses=("pending", "scheduled", "draft")):
    hits = []
    for s in all_docs():
        if s.get("accountId") != ACC.STUDIOSOFT_THREADS:
            continue
        if (s.get("status") or "").lower() not in statuses:
            continue
        for m in (s.get("medias") or []):
            b = os.path.basename((m.get("url") or "").split("?")[0]).lower()
            if b in [f.lower() for f in MEDIA_FILES]:
                hits.append(((s.get("scheduleAt") or "")[:16], s.get("status"),
                             (s.get("title") or "")[:40], s.get("_id") or s.get("id")))
                break
    return hits


def next_free_09():
    busy = {(s.get("scheduleAt") or "")[:19] for s in all_docs()
            if s.get("accountId") == ACC.STUDIOSOFT_THREADS
            and (s.get("status") or "").lower() in ("pending", "scheduled", "draft")}
    now = datetime.now(timezone.utc)
    start = datetime(now.year, now.month, now.day, tzinfo=timezone.utc)
    if now.hour >= 2:
        start += timedelta(days=1)
    for day in range(0, 20):
        cand = (start + timedelta(days=day)).strftime("%Y-%m-%dT02:00:00")
        if cand not in busy:
            lab = (datetime.fromisoformat(cand) + timedelta(hours=7)).strftime("%d %b %Y 09:00 WIB")
            return cand + ".000Z", lab
    return None, None


def main():
    print("1) IDEMPOTENSI:")
    hits = scan_media(("pending", "scheduled", "draft", "success", "error"))
    if hits:
        print("   media hc42 SUDAH ada -> tidak create:", hits)
        return True
    print("   belum ada")

    print("\n2) MEDIA PIL + 2 ingress:")
    ok = True
    for f in MEDIA_FILES:
        im = Image.open(os.path.join(IMG_DIR, f)); im.verify()
        im = Image.open(os.path.join(IMG_DIR, f))
        print("   PIL %s %s %d bytes" % (f, im.size, os.path.getsize(os.path.join(IMG_DIR, f))))
    for u in MEDIA_URLS:
        for ip in INGRESS:
            code = "000"
            for _ in range(4):
                r = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
                                    "--max-time", "60", "--resolve",
                                    "mantapserver.tail3947bb.ts.net:443:%s" % ip, u],
                                   capture_output=True, text=True)
                code = r.stdout.strip()
                if code == "200":
                    break
            print("   %s @%s: %s" % (u.split("/")[-1], ip, code))
            if code != "200":
                ok = False
    if not ok:
        print("   media tidak 200 -> batal")
        return False

    cap = THREADS_TXT
    if not cap:
        print("\n!! /tmp/hc42_threads_caption.txt tidak ada — jalankan: python3 -c import script")
        return False
    print("\n3) caption Threads %d char" % len(cap))

    print("\n4) SLOT:")
    SLOT_UTC, SLOT_LABEL = next_free_09()
    print("   carousel Threads: %s (%s)" % (SLOT_LABEL, SLOT_UTC))

    base_dt = datetime.fromisoformat(SLOT_UTC.replace("Z", "+00:00"))
    r2 = (base_dt + timedelta(minutes=1)).strftime("%Y-%m-%dT%H:%M:%S.000Z")
    r3 = (base_dt + timedelta(minutes=2)).strftime("%Y-%m-%dT%H:%M:%S.000Z")
    medias = [c.make_media(u, "image", "slide%d" % (i + 1)) for i, u in enumerate(MEDIA_URLS)]

    print("\n5) CREATE album (dengan retry):")
    pid = None
    for attempt in range(1, 5):
        try:
            alb = c.schedule_album(ACC.STUDIOSOFT_THREADS, cap, SLOT_UTC, medias, title=TITLE)
            pid = alb.get("scheduleId") or alb.get("_id") or alb.get("id")
            print("   attempt %d -> OK %s" % (attempt, pid))
            break
        except Exception as e:
            print("   attempt %d GAGAL: %s" % (attempt, str(e)[:180]))
            time.sleep(8 * attempt)
    if not pid:
        print("   album gagal total")
        return False

    print("\n6) REPLIES:")
    for txt, at in ((REPLY1, r2), (REPLY2, r3)):
        for attempt in range(1, 4):
            try:
                res = c.create_schedule(ACC.STUDIOSOFT_THREADS, txt, at, type_="text", replies=[pid])
                print("   reply %s -> %s" % (at[11:16], res.get("scheduleId") or res.get("_id") or res.get("id")))
                break
            except Exception as e:
                print("   reply attempt %d GAGAL: %s" % (attempt, str(e)[:150]))
                time.sleep(6 * attempt)

    print("\n7) VERIFIKASI per-ID:")
    d = get_retry("/public/schedule/%s" % pid)
    doc = d.get("doc") or d.get("data") or d
    print("   ALBUM %s status=%s at=%s type=%s medias=%d title=%s" % (
        pid, doc.get("status"), doc.get("scheduleAt"), doc.get("type"),
        len(doc.get("medias") or []), (doc.get("title") or "")[:50]))
    for m in (doc.get("medias") or []):
        print("      -", m.get("url"))
    print("   scan pending dgn media hc42:", scan_media(("pending", "scheduled", "draft")))
    open("/tmp/hc42_threads_album_id.txt", "w").write(str(pid))
    return True


if __name__ == "__main__":
    sys.exit(0 if main() else 1)
