#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Pasang carousel TS Law v2 (jumlah anggapan dibuat bervariasi, tidak 8 semua).

Deck baru: deck_tslaw_<seri>_v2.json  (dibuat variasikan_carousel_tslaw.py)
Slide baru: /tmp/<seri>_v2/tslaw_gen_NN.png (dari gen_tslaw_slide.py)

  python3 pasang_carousel_tslaw_v2.py            # preview: validasi caption saja, tidak menyentuh apa pun
  python3 pasang_carousel_tslaw_v2.py --go       # tukar JPEG di openclaw-img + update 18 jadwal + verifikasi

Hashtag & nada mengikuti caption lama (tanpa hashtag besar, tanpa mention, tanpa CJK).
"""
import json
import os
import re
import subprocess
import sys
import time

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

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
IMG = f"{WS}/openclaw-img"
URLBASE = "https://mantapserver.tail3947bb.ts.net/openclaw-img/"
INGRESS = ["103.84.155.153", "103.84.155.217"]
HOST = "mantapserver.tail3947bb.ts.net"

TAIL = """
Geser slide-nya sampai habis ya, tiap slide ada bagian mitos dan faktanya.

Kalau kalian punya anggapan hukum lain yang bikin ragu, tulis di kolom komentar 👇

Butuh pendampingan hukum? Konsultasikan dengan Tito Suprianto Law Firm: https://tslaw.id

📲 WhatsApp: +62 819-0922-2026

Konten ini edukasi umum, bukan nasihat hukum untuk kasus spesifik."""

TH_CTA = "Anggapan mana yang paling sering kamu dengar? Tulis di kolom komentar 👇"

# seri: (prefix file, judul, N, item daftar IG/FB, hashtag IG/FB, caption Threads)
SERI = {
    "mitos10": dict(
        n=10,
        judul="TS Law — Carousel Mitos atau Fakta: 10 Anggapan Hukum",
        pembuka="Mitos atau Fakta? Ada 10 anggapan hukum yang sering dipercaya, padahal keliru. ⚖️",
        penutup="Kesepuluhnya sering bikin orang salah langkah, karena keputusan diambil berdasarkan asumsi, bukan aturan yang berlaku.",
        items=[
            "Perkara pidana harus dilaporkan dalam 24 jam, kalau tidak perkaranya hilang.",
            "Chat WhatsApp tidak bisa dijadikan bukti di pengadilan.",
            "Rekaman pembicaraan tanpa izin pasti tidak sah.",
            "Pisah rumah lama otomatis dianggap bercerai.",
            "Anak di bawah umur bebas dari proses hukum.",
            "Karya belum didaftarkan berarti belum dilindungi hak cipta.",
            "Barang belanja online cacat bukan tanggung jawab penjual.",
            "Karyawan bisa diberhentikan sepihak kapan saja.",
            "Tidak bisa bayar utang langsung masuk penjara.",
            "Semua sengketa harus lewat pengadilan.",
        ],
        tags="#mitosataufakta #hukumpidana #hukumperdata #hakcipta #ketenagakerjaan #hukumacara #edukasihukum #tslaw",
        th=("Mitos atau fakta? Sepuluh anggapan hukum ini sering dipercaya, padahal keliru. ⚖️\n\n"
            "Chat WhatsApp katanya tidak bisa jadi bukti. Tidak bayar utang katanya langsung masuk penjara. "
            "Semua sengketa katanya wajib lewat pengadilan.\n\n"
            f"Kesepuluhnya kami bahas di carousel ini, tiap slide ada sisi mitos dan faktanya.\n\n{TH_CTA}\n\n"
            "#mitosataufakta #hukumpidana #edukasihukum #tslaw"),
    ),
    "mitosproses": dict(
        n=7,
        judul="TS Law — Carousel Mitos atau Fakta: 7 Anggapan soal Proses Hukum",
        pembuka="Mitos atau Fakta? Ada 7 anggapan soal proses hukum yang sering dipercaya, padahal keliru. ⚖️",
        penutup="Ketujuhnya sering bikin orang salah langkah, karena keputusan diambil berdasarkan asumsi, bukan aturan yang berlaku.",
        items=[
            "Somasi itu sama dengan panggilan pengadilan.",
            "Tidak punya biaya berarti tidak bisa menuntut hak.",
            "Damai cukup disepakati lisan, tidak perlu ditulis.",
            "Semua perkara wajib pakai pengacara.",
            "Menunda menuntut hak tidak ada akibatnya.",
            "Surat kuasa bebas diisi apa saja.",
            "Mediasi cuma buang waktu.",
        ],
        tags="#mitosataufakta #hukumacara #hukumperdata #hukumacaraperdata #edukasihukum #proseshukum #tslaw",
        th=("Mitos atau fakta? Tujuh anggapan soal proses hukum ini sering dipercaya, padahal keliru. ⚖️\n\n"
            "Somasi katanya sama dengan panggilan pengadilan. Damai katanya cukup disepakati lisan. "
            "Mediasi katanya cuma buang waktu.\n\n"
            f"Ketujuhnya kami bahas di carousel ini, tiap slide ada sisi mitos dan faktanya.\n\n{TH_CTA}\n\n"
            "#mitosataufakta #hukumacara #edukasihukum #tslaw"),
    ),
    "mitoshak": dict(
        n=6,
        judul="TS Law — Carousel Mitos atau Fakta: 6 Anggapan soal Hak dan Kewajiban",
        pembuka="Mitos atau Fakta? Ada 6 anggapan soal hak dan kewajiban yang sering dipercaya, padahal keliru. ⚖️",
        penutup="Keenamnya sering bikin orang salah langkah, karena keputusan diambil berdasarkan asumsi, bukan aturan yang berlaku.",
        items=[
            "Kontrak bisa dibatalkan sepihak kalau merasa dirugikan.",
            "Uang muka otomatis hangus kalau pembeli membatalkan.",
            "Pemilik kontrakan bisa mengeluarkan penyewa kapan saja.",
            "Tanpa kwitansi, pembayaran dianggap tidak pernah ada.",
            "Kesepakatan lewat chat tidak punya kekuatan apa pun.",
            "Kalau perusahaan bangkrut, pemilik ikut menanggung semua utang.",
        ],
        tags="#mitosataufakta #hukumperdata #hukumbisnis #ketenagakerjaan #perjanjian #edukasihukum #tslaw",
        th=("Mitos atau fakta? Enam anggapan soal hak dan kewajiban ini keliru. ⚖️\n\n"
            "Uang muka katanya otomatis hangus kalau pembeli membatalkan. Tanpa kwitansi katanya pembayaran "
            "dianggap tidak pernah ada. Kesepakatan lewat chat katanya tidak berkekuatan apa pun.\n\n"
            f"Keenamnya kami bahas di carousel ini, tiap slide ada sisi mitos dan faktanya.\n\n{TH_CTA}\n\n"
            "#mitosataufakta #hukumperdata #edukasihukum #tslaw"),
    ),
    "mitoskerja": dict(
        n=5,
        judul="TS Law — Carousel Mitos atau Fakta: 5 Anggapan soal Kerja dan Perusahaan",
        pembuka="Mitos atau Fakta? Ada 5 anggapan soal kerja dan perusahaan yang sering dipercaya, padahal keliru. ⚖️",
        penutup="Kelima anggapan itu sering bikin orang salah langkah, karena keputusan diambil berdasarkan asumsi, bukan aturan yang berlaku.",
        items=[
            "Resign tanpa pemberitahuan tidak ada konsekuensinya.",
            "Gaji boleh ditahan sebagai jaminan.",
            "Kontrak kerja bisa diperpanjang terus tanpa batas.",
            "Yang mengundurkan diri kehilangan semua haknya.",
            "Pekerja tidak perlu paham isi kontraknya.",
        ],
        tags="#mitosataufakta #ketenagakerjaan #hukumketenagakerjaan #hubunganindustrial #hukumbisnis #edukasihukum #tslaw",
        th=("Mitos atau fakta? Lima anggapan soal kerja dan perusahaan ini keliru. ⚖️\n\n"
            "Resign katanya tanpa konsekuensi. Gaji katanya boleh ditahan sebagai jaminan. Kontrak kerja "
            "katanya bisa diperpanjang terus tanpa batas.\n\n"
            "Ketiganya diatur, bukan diserahkan ke kebiasaan kantor. Kelimanya kami bahas di carousel ini, "
            f"tiap slide ada sisi mitos dan faktanya.\n\n{TH_CTA}\n\n"
            "#mitosataufakta #ketenagakerjaan #edukasihukum #tslaw"),
    ),
    "mitosbukti": dict(
        n=6,
        judul="TS Law — Carousel Mitos atau Fakta: 6 Anggapan soal Bukti dan Hak",
        pembuka="Mitos atau Fakta? Ada 6 anggapan soal bukti dan hak yang sering dipercaya, padahal keliru. ⚖️",
        penutup="Keenamnya sering bikin orang salah langkah, karena keputusan diambil berdasarkan asumsi, bukan aturan yang berlaku.",
        items=[
            "Tanpa saksi mata, perkara tidak bisa jalan.",
            "Laporan dicabut, perkara otomatis berhenti.",
            "Tidak ada kontrak tertulis berarti tidak ada hubungan kerja.",
            "Ganti rugi hanya bisa lewat pengadilan.",
            "Salah tangkap, ya sudah, tidak ada hak apa-apa.",
            "Tidak tahu aturannya, jadi tidak bisa disalahkan.",
        ],
        tags="#mitosataufakta #hukumacara #hukumpembuktian #hukumperdata #ketenagakerjaan #edukasihukum #tslaw",
        th=("Mitos atau fakta? Enam anggapan soal bukti dan hak ini keliru. ⚖️\n\n"
            "Tanpa saksi mata katanya perkara tidak jalan. Laporan dicabut katanya perkara berhenti. "
            "Tidak tahu aturannya katanya tidak bisa disalahkan.\n\n"
            "Ketiganya yang paling sering bikin orang memilih diam. Keenamnya kami bahas di carousel ini, "
            f"tiap slide ada sisi mitos dan faktanya.\n\n{TH_CTA}\n\n"
            "#mitosataufakta #hukumacara #edukasihukum #tslaw"),
    ),
    "mitostanah": dict(
        n=7,
        judul="TS Law — Carousel Mitos atau Fakta: 7 Anggapan soal Tanah dan Properti",
        pembuka="Mitos atau Fakta? Ada 7 anggapan soal tanah dan properti yang sering dipercaya, padahal keliru. ⚖️",
        penutup="Ketujuhnya sering bikin orang salah langkah, karena keputusan diambil berdasarkan asumsi, bukan aturan yang berlaku.",
        items=[
            "Sertifikat hilang, berarti tanahnya hilang.",
            "Sudah bayar lunas, otomatis jadi pemilik.",
            "Tanah lama dibiarkan otomatis jadi milik yang menggarap.",
            "Telat bayar cicilan sekali, rumah langsung disita.",
            "Tanah sendiri, bebas dibangun apa saja.",
            "Notaris bisa mengurus semuanya tanpa dokumen.",
            "Cek tanah cukup lihat fisiknya saja.",
        ],
        tags="#mitosataufakta #hukumproperti #hukumpertanahan #sertifikattanah #hukumperdata #edukasihukum #tslaw",
        th=("Mitos atau fakta? Tujuh anggapan soal tanah dan properti ini sering dipercaya, padahal keliru. ⚖️\n\n"
            "Sudah bayar lunas katanya otomatis jadi pemilik. Sertifikat hilang katanya tanahnya ikut hilang. "
            "Telat bayar cicilan sekali katanya rumah langsung disita.\n\n"
            f"Ketujuhnya kami bahas di carousel ini, tiap slide ada sisi mitos dan faktanya.\n\n{TH_CTA}\n\n"
            "#mitosataufakta #hukumproperti #edukasihukum #tslaw"),
    ),
}

AKUN = {ACC.TSLAW_IG: "IG", ACC.TSLAW_FB: "FB", ACC.TSLAW_THREADS: "Threads"}
CTA_RE = re.compile(r"komentar|tulis di|menurut (kamu|anda)|setuju|pendapat", re.I)
MENTION_RE = re.compile(r"@\w+")
CJK = re.compile(r"[\u3000-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff00-\uffef]")


def caption_ig(s):
    daftar = "\n".join(f"{i}. {t}" for i, t in enumerate(s["items"], 1))
    return (f"{s['pembuka']}\n\nKami rangkum dalam satu carousel biar gampang dibaca:\n\n{daftar}\n\n"
            f"{s['penutup']}{TAIL}\n\n{s['tags']}")


def validasi(nama, cap, batas, wajib_link=True):
    m = []
    if len(cap) > batas:
        m.append(f"panjang={len(cap)}>{batas}")
    if not CTA_RE.search(cap):
        m.append("tanpa-CTA")
    if MENTION_RE.search(cap):
        m.append("mention")
    if CJK.search(cap):
        m.append("CJK")
    tags = re.findall(r"#(\w+)", cap)
    if any(t != t.lower() for t in tags):
        m.append("hashtag-besar")
    # Seri carousel TS Law: link artikel hanya di IG/FB; caption Threads cukup hashtag
    # (sama seperti 18 jadwal yang sekarang tayang — jangan diubah di luar pola itu).
    if wajib_link and "http" not in cap:
        m.append("tanpa-link")
    print(f"  {nama:8} len={len(cap):4} tags={len(tags):2} {'✅' if not m else '❌ ' + ','.join(m)}")
    return m


def gate(url):
    hasil = {}
    for label, extra in (("lokal", []),
                         *[(ip, ["--resolve", f"{HOST}:443:{ip}"]) for ip in INGRESS]):
        p = subprocess.run(["curl", "-4", "-s", "-o", "/dev/null", "-w", "%{http_code}",
                            "--max-time", "25", *extra, url], capture_output=True, text=True)
        hasil[label] = (p.stdout or "000").strip()
    return hasil


def semua_jadwal(c):
    docs, page = [], 1
    while True:
        r = c.get(f"/public/schedule?page={page}&limit=100")
        d = r.get("docs", [])
        if not d:
            break
        docs += d
        if page >= r.get("totalPages", 1):
            break
        page += 1
    return docs


def main():
    go = "--go" in sys.argv
    c = get_client()

    print("=== VALIDASI CAPTION v2 ===")
    cap = {}
    for seri, s in SERI.items():
        cap[seri] = {"IG": caption_ig(s), "FB": caption_ig(s), "Threads": s["th"]}
        print(f"[{seri}]")
        for ch in ("IG", "FB", "Threads"):
            validasi(ch, cap[seri][ch], 500 if ch == "Threads" else 2200, wajib_link=(ch != "Threads"))

    if not go:
        print("\n(preview saja — jalankan dengan --go untuk menukar media + update jadwal)")
        return

    # ── 1) tukar JPEG di openclaw-img (nama file SAMA, jadi URL tidak berubah) ──
    from PIL import Image
    print("\n=== TUKAR MEDIA ===")
    for seri, s in SERI.items():
        n_slide = s["n"] + 2
        for i in range(1, n_slide + 1):
            src = f"/tmp/{seri}_v2/tslaw_gen_{i:02d}.png"
            dst = f"{IMG}/tslaw_{seri}_{i:02d}.jpg"
            im = Image.open(src).convert("RGB")
            assert im.size == (1080, 1350), (src, im.size)
            im.save(dst, "JPEG", quality=90, optimize=True)
        print(f"  {seri}: {n_slide} slide -> openclaw-img/tslaw_{seri}_NN.jpg")

    # ── 2) gate 200 di 3 jalur sebelum menyentuh jadwal ──
    print("\n=== GATE MEDIA ===")
    for seri, s in SERI.items():
        for i in range(1, s["n"] + 3):
            u = f"{URLBASE}tslaw_{seri}_{i:02d}.jpg"
            g = gate(u)
            if not all(v == "200" for v in g.values()):
                print(f"  ❌ {u} {g}")
                sys.exit(1)
        print(f"  ✅ {seri}: {s['n'] + 2} media 200 di 3 jalur")

    # ── 3) update 18 jadwal ──
    print("\n=== UPDATE JADWAL ===")
    docs = semua_jadwal(c)
    for seri, s in SERI.items():
        slide = [f"tslaw_{seri}_{i:02d}.jpg" for i in range(1, s["n"] + 3)]
        target = [d for d in docs
                  if d.get("accountId") in AKUN
                  and d.get("status") == "pending"
                  and str(d.get("type", "")).lower() == "album"
                  and (d.get("medias") or [{}])[0].get("url", "").endswith(f"tslaw_{seri}_01.jpg")]
        if len(target) != 3:
            print(f"  ⚠️ {seri}: ketemu {len(target)} jadwal (harusnya 3) — dilewati")
            continue
        for d in target:
            ch = AKUN[d["accountId"]]
            sid = d["_id"]
            c.update_schedule(sid, {
                "title": s["judul"],
                "description": cap[seri][ch],
                "medias": [{"url": URLBASE + f} for f in slide],
                "topic": d.get("topic") or "Mitos atau Fakta Hukum",
                "type": "album",
                "replies": [],
            })
            time.sleep(0.4)
            b = c.get_schedule(sid)
            bb = b.get("data", b) if isinstance(b, dict) else b
            med = [m.get("url", "").split("/")[-1] for m in (bb.get("medias") or [])]
            desc = bb.get("description") or ""
            ok = (bb.get("status") == "pending" and med == slide and desc == cap[seri][ch]
                  and bb.get("title") == s["judul"])
            print(f"  [{'✅' if ok else '❌'}] {seri:12} {ch:7} {sid} | {bb.get('scheduleAt')} | "
                  f"media={len(med)} | caption={len(desc)} char | {bb.get('status')}")

        # bersihkan sisa slide lama yang sudah tidak dipakai (hanya kalau lebih pendek)
        sisa = [f for f in os.listdir(IMG)
                if f.startswith(f"tslaw_{seri}_") and f not in slide]
        if sisa:
            print(f"    (sisa file lama dibiarkan di server: {sorted(sisa)})")


if __name__ == "__main__":
    main()
