#!/usr/bin/env python3
"""StudioSoft Healthcare — hc33 = RE-AIR hc19 "Landing Page Pendaftaran Online RS & Klinik".

Konteks (cron run 11 Sep 2026, 02:00 WIB):
- Stok artikel healthcare studiosoft.id HABIS (16 slug hc01-hc31 + mental-health hc32;
  tidak ada artikel baru sejak 3 Sep 2026 — diverifikasi via WP REST lewat proxy).
- hc19/hc20/hc21 TIDAK PERNAH tayang: semua jadwalnya error karena URL media BARE
  (tanpa prefix /openclaw-img/) -> "The media could not be fetched from this URI".
- Maka run ini me-re-air hc19 (topik belum pernah tayang di platform mana pun) dengan
  URL media yang sudah diperbaiki + verifikasi jalur INTERNET (dua ingress funnel).

ATURAN (5 Sep + koreksi hc30-hc32):
- LinkedIn StudioSoft: SKIP (text-only dari artikel, artikel ini sudah punya jadwal text ss_li).
- Threads + FB: album carousel OK. IG jangan disentuh (carousel SSIGSEP jalan sendiri).
- FB: medias album, replies KOSONG. Threads: album + 2 replies.
- Hashtag huruf kecil semua, 0 mention internal, caption wajib pancingan diskusi.
- Slot: pakai slot KOSONG BERSAMA Threads+FB berikutnya (7-slot rule) -> 14 Sep 2026 17:00 WIB.
"""
import json, os, re, subprocess, sys
from datetime import datetime, timezone, timedelta

sys.path.insert(0, "/home/mantapman/.openclaw/workspace-atun")
from repliz_client import ReplizClient, ACC
from diskusi_engine import tambahkan_diskusi

DRY = os.environ.get("DRY", "") == "1"

c = ReplizClient()

SLOT_UTC = "2026-09-14T10:00:00.000Z"   # 14 Sep 2026 17:00 WIB (slot kosong bersama Threads+FB)
TITLE = "Landing Page Pendaftaran Online RS & Klinik"
ARTICLE_URL = "https://studiosoft.id/strategi-digital-marketing-rumah-sakit/"
HASHTAG_LINE = "#studiosoft #landingpagers #digitalmarketing #rumahsakit #klinik"
MEDIA_URLS = [
    "https://mantapserver.tail3947bb.ts.net/openclaw-img/ss_hc19_landing_01_cover.jpg",
    "https://mantapserver.tail3947bb.ts.net/openclaw-img/ss_hc19_landing_02_kenapa.jpg",
    "https://mantapserver.tail3947bb.ts.net/openclaw-img/ss_hc19_landing_03_isi.jpg",
    "https://mantapserver.tail3947bb.ts.net/openclaw-img/ss_hc19_landing_04_langkah.jpg",
    "https://mantapserver.tail3947bb.ts.net/openclaw-img/ss_hc19_landing_05_cta.jpg",
]

THREADS_BASE = ("Landing page pendaftaran online itu pintu masuk pasien baru, tapi sering dilupakan.\n"
               "\n"
               "Padahal cukup sediakan:\n"
               "✅ Info layanan & jadwal dokter\n"
               "✅ Formulir daftar yang singkat\n"
               "✅ Tombol \"DAFTAR SEKARANG\" mencolok\n"
               "✅ Lokasi & nomor WA yang jelas\n"
               "\n"
               "Satu halaman yang rapi bisa menata semua alur pendaftaran.")

FB_BASE = ("Halaman pendaftaran online sering jadi \"anak tiri\" di website RS & klinik. Padahal di "
           "sinilah calon pasien memutuskan mau datang atau tidak.\n"
           "\n"
           "Empat elemen yang wajib ada:\n"
           "1. Informasi layanan & jadwal dokter\n"
           "2. Formulir pendaftaran yang singkat\n"
           "3. Tombol CTA \"DAFTAR SEKARANG\" yang menonjol\n"
           "4. Lokasi, peta, dan kontak yang mudah diakses\n"
           "\n"
           "Bold statement: kalau halaman pendaftaran sulit dipakai, pasien pindah ke fasyankes yang "
           "lebih mudah — diam-diam.\n"
           "\n"
           f"Baca artikel lengkapnya: {ARTICLE_URL}\n"
           "\n"
           f"{HASHTAG_LINE}")


CTA_RE = re.compile(r"komentar|pendapat|diskusi|setuju|share|pengalaman|menurut", re.I)


def build_threads(max_try=40):
    """Pitfall: pancingan random bisa tanpa ajakan komentar -> undi ulang sampai lolos CTA+<=500."""
    for _ in range(max_try):
        txt = tambahkan_diskusi(THREADS_BASE, platform="threads", industri="rumah_sakit",
                                tone="netral", force=True)
        if CTA_RE.search(txt) and len(txt) <= 500:
            return txt
    return None


def build_fb(max_try=40):
    for _ in range(max_try):
        txt = tambahkan_diskusi(FB_BASE, platform="facebook", industri="rumah_sakit",
                                tone="opini", force=True)
        if CTA_RE.search(txt):
            return txt
    return None


THREADS = build_threads()
FB = build_fb()

REPLY1 = (f"Baca selengkapnya: {ARTICLE_URL}\n\n"
          "Konsultasi landing page RS/klinik & alur pendaftaran online:\nwww.studiosoft.id")
REPLY2 = HASHTAG_LINE

CTA_RE = re.compile(r"komentar|pendapat|diskusi|setuju|share|pengalaman|menurut", re.I)


def check_caption(name, txt, limit=None, require_cta=True):
    ok = True
    if limit and len(txt) > limit:
        print(f"  ❌ {name}: {len(txt)} char > {limit}")
        ok = False
    m = re.findall(r"@\w+", txt)
    if m:
        print(f"  ❌ {name}: ada mention {m}")
        ok = False
    caps = [t for t in re.findall(r"#(\w+)", txt) if t != t.lower()]
    if caps:
        print(f"  ❌ {name}: hashtag KAPITAL {caps}")
        ok = False
    if require_cta and not CTA_RE.search(txt):
        print(f"  ❌ {name}: tidak ada pancingan diskusi")
        ok = False
    print(f"  {'✅' if ok else '⚠️'} {name}: {len(txt)} char")
    return ok


def verify_urls_internet():
    """Verifikasi tiap media lewat jalur INTERNET (paksa resolve ke ingress funnel)."""
    ips = subprocess.run(["dig", "+short", "mantapserver.tail3947bb.ts.net", "A", "@1.1.1.1"],
                         capture_output=True, text=True).stdout.split()
    ips = [i for i in ips if i.count(".") == 3]
    ok = True
    for u in MEDIA_URLS:
        for ip in ips[:2]:
            r = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
                                "--max-time", "20", "--resolve",
                                f"mantapserver.tail3947bb.ts.net:443:{ip}", u],
                               capture_output=True, text=True)
            code = r.stdout.strip()
            print(f"  {u.split('/')[-1]} @{ip}: {code}")
            if code != "200":
                ok = False
    return ok


def already_scheduled():
    """Idempoten: cek apakah media ss_hc19_landing_01_cover.jpg sudah ada di pending TH/FB."""
    need = "ss_hc19_landing_01_cover.jpg"
    hits = []
    page = 1
    while True:
        d = c.get(f"/public/schedule?page={page}&limit=100")
        for s in d.get("docs", []):
            if s.get("accountId") not in (ACC.STUDIOSOFT_THREADS, ACC.STUDIOSOFT_FB):
                continue
            if (s.get("status") or "").lower() not in ("pending", "scheduled", "draft"):
                continue
            if any(need in (m.get("url") or "") for m in (s.get("medias") or [])):
                hits.append((s.get("accountId"), (s.get("scheduleAt") or "")[:16], s.get("type")))
        if page >= (d.get("totalPages") or 1):
            break
        page += 1
    return hits


def verify(need="ss_hc19_landing_01_cover.jpg"):
    hits = []
    page = 1
    while True:
        d = c.get(f"/public/schedule?page={page}&limit=100")
        for s in d.get("docs", []):
            if s.get("accountId") not in (ACC.STUDIOSOFT_THREADS, ACC.STUDIOSOFT_FB):
                continue
            if (s.get("status") or "").lower() != "pending":
                continue
            if any(need in (m.get("url") or "") for m in (s.get("medias") or [])):
                ms = len(s.get("medias") or [])
                hits.append((s.get("accountId"), (s.get("scheduleAt") or "")[:16],
                             (s.get("title") or "")[:45], s.get("type"), ms,
                             len(s.get("replies") or [])))
        if page >= (d.get("totalPages") or 1):
            break
        page += 1
    return hits


def slot_conflict(aids, slot_utc):
    """True kalau slot (window 6 menit) sudah terisi di salah satu akun (piranti anti double-book)."""
    base = datetime.fromisoformat(slot_utc.replace("Z", "+00:00"))
    busy = set()
    page = 1
    while True:
        d = c.get(f"/public/schedule?page={page}&limit=100")
        for s in d.get("docs", []):
            if s.get("accountId") in aids and (s.get("status") or "").lower() in ("pending", "scheduled", "draft"):
                st = (s.get("scheduleAt") or "")[:19]
                if st:
                    busy.add(st)
        if page >= (d.get("totalPages") or 1):
            break
        page += 1
    clash = []
    for off in range(6):
        key = (base + timedelta(minutes=off)).strftime("%Y-%m-%dT%H:%M:%S")
        if key in busy:
            clash.append(key)
    return clash


def main():
    wib = datetime.now(timezone(timedelta(hours=7)))
    print(f"Time WIB: {wib.strftime('%Y-%m-%d %H:%M')}")
    print(f"Slot: {SLOT_UTC} (14 Sep 2026 17:00 WIB)")
    print("\nCEK SLOT KOSONG (Threads+FB):")
    clash = slot_conflict([ACC.STUDIOSOFT_THREADS, ACC.STUDIOSOFT_FB], SLOT_UTC)
    if clash:
        print(f"  ❌ slot sudah terisi: {clash} — batal, cari slot lain.")
        return False
    print("  ✅ slot kosong di Threads & FB")
    print("\nCEK CAPTION:")
    if not THREADS or not FB:
        print("  ❌ gagal menyusun caption dgn pancingan diskusi — batal.")
        return False
    ok = True
    ok &= check_caption("Threads", THREADS, 500)
    ok &= check_caption("FB", FB)
    ok &= check_caption("Reply1", REPLY1, require_cta=False)
    ok &= check_caption("Reply2", REPLY2, require_cta=False)
    if not ok:
        print("\n❌ Caption gagal aturan — batal.")
        return False

    hits = already_scheduled()
    if hits:
        print("\n⚠️ Media sudah ada di pending (idempoten, SKIP create):")
        for h in hits:
            print("  ", h)
        return True

    print("\nVERIFIKASI MEDIA JALUR INTERNET:")
    if not verify_urls_internet():
        print("❌ Ada media tidak 200 dari internet — batal.")
        return False

    if DRY:
        print("\n[DRY RUN] caption siap; tidak ada create.")
        return True

    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", f"slide{i+1}") for i, u in enumerate(MEDIA_URLS)]

    results = {}
    print("\nTHREADS:")
    try:
        album = c.schedule_album(ACC.STUDIOSOFT_THREADS, THREADS, SLOT_UTC, medias, title=TITLE)
        pid = album.get("scheduleId") or album.get("_id") or album.get("id")
        print(f"  OK album -> {pid}")
        c.create_schedule(ACC.STUDIOSOFT_THREADS, REPLY1, r2, type_="text", replies=[pid])
        c.create_schedule(ACC.STUDIOSOFT_THREADS, REPLY2, r3, type_="text", replies=[pid])
        print("  OK 2 replies")
        results["threads"] = True
    except Exception as e:
        print(f"  GAGAL {e}")
        results["threads"] = False

    print("\nFACEBOOK:")
    try:
        album = c.schedule_album(ACC.STUDIOSOFT_FB, FB, SLOT_UTC, medias, title=TITLE)
        pid = album.get("scheduleId") or album.get("_id") or album.get("id")
        print(f"  OK album -> {pid}")
        results["fb"] = True
    except Exception as e:
        print(f"  GAGAL {e}")
        results["fb"] = False

    print("\n" + "=" * 55)
    ok = all(results.values())
    print("Semua platform dijadwalkan!" if ok else f"Gagal: {[k for k, v in results.items() if not v]}")

    if ok:
        print("\nVERIFIKASI (re-list pending):")
        for h in verify():
            print("  ", h)
        with open("/home/mantapman/.openclaw/workspace-atun/studiosoft_healthcare_log.txt", "a") as f:
            f.write(f"\n[{wib.strftime('%Y-%m-%d %H:%M')} WIB] hc33 (RE-AIR hc19) | {TITLE} | "
                    f"{ARTICLE_URL} | Threads+FB album 14 Sep 17:00 WIB (10:00Z), +2 replies Threads | "
                    f"LinkedIn SKIP | catatan: stok artikel healthcare masih HABIS (0 artikel baru sejak 3 Sep); "
                    f"hc19 belum pernah tayang (error URL media bare) -> dijadwalkan ulang dgn URL /openclaw-img/ terverifikasi 200 jalur internet. "
                    f"BUTUH artikel healthcare baru dari Bos.\n")
        print("Log ditulis.")
    return ok


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