#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""TS Law — carousel "Sudah divonis narkotika, masih bisa PK?" (aset Bos 5 Okt 2026, ts2.zip).

6 slide 1.png..6.png (1080x1350) dari Bos -> JPEG q90 `tslaw_pk_narkotika_01..06.jpg`.
Tayang **8 Okt 2026** (semua akun TSLaw bebas post feed hari itu; 6 Okt sudah dipakai video PMH):
  IG      09:00 WIB (02:00Z)  — aturan carousel = 09:00
  Threads 09:00 WIB (02:00Z)
  FB      19:30 WIB (12:30Z)
LinkedIn TSLaw TETAP SKIP (STOP sejak 10 Sep).
IDEMPOTEN: skip kalau nama file slide pertama sudah ada di jadwal akun itu.
URUTAN: medias[] dipasang 01..06 sesuai nama file kiriman Bos (1.png..6.png).
"""
import sys, json, re, subprocess, urllib.parse, urllib.request

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

IG = "6a76a54d62caae1e04f30968"
THREADS = "6a35f8b7c5ff4ce3a322b2ed"
FB = "6a3b41d1c5ff4ce3a32753e8"

IMG = "https://mantapserver.tail3947bb.ts.net/openclaw-img/"
SLIDES = [f"tslaw_pk_narkotika_{i:02d}.jpg" for i in range(1, 7)]
URLS = [IMG + f for f in SLIDES]

CAP = """Sudah divonis bersalah dalam perkara narkotika, apakah masih bisa diperjuangkan? Jawabannya, masih. Lewat Peninjauan Kembali. ⚖️

PK itu upaya hukum luar biasa, jadi baru bisa diajukan kalau putusannya sudah berkekuatan hukum tetap. Bukan pengganti banding atau kasasi.

Tapi ini yang sering salah dipahami: PK bukan jalur buat minta hakim sekadar mengurangi hukuman. Harus ada alasan hukum yang jelas, dan itu cuma tiga:

1. Ditemukan keadaan atau bukti baru
2. Ada pertentangan antara putusan-putusan
3. Kekhilafan hakim atau kekeliruan yang nyata

Dasar hukumnya ada di Pasal 318 Undang-Undang Nomor 20 Tahun 2025 tentang Kitab Undang-Undang Acara Pidana.

Jadi kalau kamu atau keluarga ada di posisi ini, yang dicek lebih dulu bukan soal ingin hukumannya lebih ringan, tapi apakah salah satu dari tiga alasan itu memang ada dan bisa dibuktikan. Kalau tidak ada, PK-nya berisiko ditolak.

Geser slide-nya sampai habis ya, urutannya kami susun biar gampang dipahami.

Kalau kalian ada pertanyaan soal perkara ini, 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.

#hukumpidana #peninjauankembali #upayahukum #narkotika #hukumacara #edukasihukum #tslaw"""

CAP_THREADS = """Sudah divonis bersalah dalam perkara narkotika, masih bisa diperjuangkan? Bisa, lewat Peninjauan Kembali (PK). ⚖️

PK itu upaya hukum luar biasa, dan bukan buat sekadar minta hukuman dikurangi. Harus ada alasan hukum yang jelas: bukti baru, pertentangan putusan, atau kekhilafan hakim yang nyata.

Geser slide-nya sampai habis ya.

Kalau kalian ada pertanyaan, tulis di kolom komentar 👇

#hukumpidana #peninjauankembali #edukasihukum #tslaw"""

JOBS = [
    ("Threads", THREADS, "2026-10-08T02:00:00.000Z", CAP_THREADS, "TS Law — Carousel PK Perkara Narkotika"),
    ("IG",      IG,      "2026-10-08T02:00:00.000Z", CAP,         "TS Law — Carousel PK Perkara Narkotika"),
    ("FB",      FB,      "2026-10-08T12:30:00.000Z", CAP,         "TS Law — Carousel PK Perkara Narkotika"),
]

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


def all_schedules():
    docs, page = [], 1
    while True:
        q = urllib.parse.urlencode({"page": page, "limit": 100})
        req = urllib.request.Request(f"{BASE}/public/schedule?{q}", headers=HEADERS)
        with urllib.request.urlopen(req, timeout=60) as r:
            d = json.load(r)
        docs += d.get("docs", d.get("data", []))
        if not d.get("hasNextPage") or not docs:
            break
        page += 1
    return docs


# 1) validasi caption
assert len(CAP) <= 2200, f"caption kepanjangan: {len(CAP)}"
assert len(CAP_THREADS) <= 500, f"caption Threads {len(CAP_THREADS)} > 500"
for label, cap in (("full", CAP), ("threads", CAP_THREADS)):
    assert "@" not in cap, f"ada mention di caption {label}"
    # Threads: CTA wajib di 160 char terakhir (caption pendek, tanpa footer).
    # Full (IG/FB): CTA ada sebelum footer link/WA/disclaimer -> cek 600 char terakhir.
    tail = cap[-160:] if label == "threads" else cap[-600:]
    assert CTA_RE.search(tail), f"ajakan komentar hilang di ekor caption {label}"
    big = [t for t in re.findall(r"#(\w+)", cap) if t != t.lower()]
    assert not big, f"hashtag huruf besar di {label}: {big}"
    assert not re.search(r"[\u3000-\u9fff\uac00-\ud7af]", cap), f"teks CJK di {label}"
print(f"caption: full {len(CAP)} char · Threads {len(CAP_THREADS)} char · CTA+hashtag+CJK OK")

# 2) validasi 6 media live lewat funnel (3 jalur)
bad = []
for fn, u in zip(SLIDES, URLS):
    codes = []
    for extra in ([], ["--resolve", "mantapserver.tail3947bb.ts.net:443:103.84.155.153"],
                  ["--resolve", "mantapserver.tail3947bb.ts.net:443:103.84.155.217"]):
        r = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
                            "--max-time", "40", "-I"] + extra + [u], capture_output=True, text=True)
        codes.append(r.stdout.strip())
    if any(c != "200" for c in codes):
        bad.append((fn, codes))
print("media 6 slide:", "SEMUA 200 (3 jalur)" if not bad else f"GAGAL {bad}")
if bad:
    sys.exit("MEDIA TIDAK 200 -> batal")

# 3) cek slot kosong + buat album (idempoten)
existing = all_schedules()
ok = 0
created = []
for label, acc, at, cap, title in JOBS:
    bentrok = [s for s in existing if s.get("accountId") == acc and s.get("scheduleAt") == at]
    if bentrok:
        t = bentrok[0].get("title") or (bentrok[0].get("medias") or [{}])[0].get("url", "")
        print(f"SKIP {label}: slot {at} sudah terisi ({t})")
        continue
    already = [s for s in existing if s.get("accountId") == acc and SLIDES[0].lower() in json.dumps(s).lower()]
    if already:
        print(f"SKIP {label}: {SLIDES[0]} sudah ada di jadwal akun ini")
        continue
    payload = {
        "accountId": acc,
        "title": title,
        "description": cap,
        "topic": "Edukasi Hukum",
        "type": "album",
        "medias": [{"url": u, "type": "image", "alt": f[:-4]} for u, f in zip(URLS, SLIDES)],
        "scheduleAt": at,
        "replies": [],
    }
    req = urllib.request.Request(f"{BASE}/public/schedule",
                                data=json.dumps(payload).encode(),
                                headers={**HEADERS, "Content-Type": "application/json"})
    try:
        with urllib.request.urlopen(req, timeout=60) as r:
            res = json.load(r)
        sid = res.get("scheduleId") or res.get("_id") or res.get("id")
        print(f"OK {label} | {at} | album {len(SLIDES)} slide | caption {len(cap)} char | id={sid}")
        created.append({"label": label, "id": sid})
        ok += 1
    except Exception as e:
        body = getattr(e, "read", lambda: b"")()
        print(f"GAGAL {label}: {e} {body[:300]}")

print(f"\n{ok} jadwal dibuat")
json.dump(created, open("/tmp/tslaw_car_pk_ids.json", "w"))
