#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""jaga_1post_threads.py — penjaga aturan "1 akun = 1 postingan Threads per hari".

Perintah Bos 16 Okt 2026: *"1 hari 1 postingan threads aja"* + *"aturan ke depan saja"*
→ jadwal yang SUDAH terpasang dibiarkan; yang dijaga hanya jadwal yang dibuat sejak aturan ini
(`--sejak`, default 2026-10-16).

Cara kerja:
  • Untuk tiap akun Threads klien aktif, hitung postingan per hari (WIB, {N} hari ke depan).
    Balasan yang dibuat sebagai jadwal terpisah ("anak reply") TIDAK dihitung sebagai postingan.
  • Kalau satu hari punya >1 postingan: sisakan SATU, kelebihannya dipindah ke tayang 2099
    (cara HOLD yang Bos pakai) — TIDAK dihapus, bisa dibalikkan.
  • Yang disisakan: (1) postingan yang sudah punya >=2 balasan, (2) yang memuat tautan artikel,
    (3) yang jam tayangnya paling awal. Postingan yang punya anak-reply tidak pernah di-HOLD
    (biar tidak ada balasan menggantung).

Pakai:
  python3 jaga_1post_threads.py                      # periksa (dry-run), 10 hari, sejak 2026-10-16
  python3 jaga_1post_threads.py --hari 14 --sejak 2026-10-01   # uji logika ke jadwal lama
  python3 jaga_1post_threads.py --go                 # jalankan (HOLD kelebihannya)
"""
import argparse
import datetime
import json
import os
import re
import sys
import time

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
DUMP = "/tmp/jaga_1post_dump.json"
OUT = os.path.join(WS, "jaga_1post_threads_log.json")
sys.path.insert(0, WS)
from repliz_client import get_client  # noqa: E402

WIB = datetime.timezone(datetime.timedelta(hours=7))
AKUN = {
    "6a334e89c5ff4ce3a3225a48": "uky", "6a335b9ec5ff4ce3a3225c2a": "ss",
    "6a35f8b7c5ff4ce3a322b2ed": "tslaw", "6a39e461c5ff4ce3a3233e09": "das",
    "6a4bbc5920e4f4f195e52960": "tsc", "6a44ed1920e4f4f195d8ecf7": "everybe",
}
HOLD = "2099-01-01T00:00:00.000Z"
MENIT_AMAN = 30


def semua_jadwal(fresh=False):
    if not fresh and os.path.exists(DUMP) and time.time() - os.path.getmtime(DUMP) < 1800:
        return json.load(open(DUMP))
    c = get_client()
    docs, page = [], 1
    while page <= 120:
        r = None
        for a in range(5):
            try:
                r = c.get_schedules(page=page, limit=100)
                break
            except Exception:
                time.sleep(4 + 2 * a)
        if r is None:
            raise SystemExit("gagal baca jadwal Repliz")
        b = r.get("docs") or []
        docs += b
        if len(b) < 100:
            break
        page += 1
    json.dump(docs, open(DUMP, "w"))
    return docs


def induk_dari(d):
    for r in d.get("replies") or []:
        if isinstance(r, dict):
            kunci = [k for k in r.keys() if k.isdigit()]
            if 8 <= len(kunci) < 40:
                return "".join(str(r[k]) for k in sorted(kunci, key=int))
    return None


def jumlah_reply(d):
    return len([r for r in (d.get("replies") or [])
                if isinstance(r, dict) and ((r.get("description") or r.get("text") or "").strip())])


def skor(d):
    """Kunci urutan: makin kecil makin diprioritaskan disisakan."""
    ada_link = 1 if re.search(r"https?://", d.get("description") or "") else 0
    return (0 if jumlah_reply(d) >= 2 else 1, 0 if ada_link else 1, d.get("scheduleAt") or "")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--hari", type=int, default=10)
    ap.add_argument("--sejak", default="2026-10-16",
                    help="hanya jadwal yang DIBUAT sejak tanggal ini (aturan ke depan)")
    ap.add_argument("--go", action="store_true")
    ap.add_argument("--fresh", action="store_true")
    a = ap.parse_args()

    docs = semua_jadwal(a.fresh)
    anak_per_induk = {}
    id_anak = set()
    for d in docs:
        p = induk_dari(d)
        if p:
            id_anak.add(d.get("_id"))
            anak_per_induk[p] = anak_per_induk.get(p, 0) + 1

    hari_ini = datetime.datetime.now(WIB).date()
    akhir = hari_ini + datetime.timedelta(days=a.hari - 1)
    batas = (datetime.datetime.now(datetime.timezone.utc)
             + datetime.timedelta(minutes=MENIT_AMAN)).strftime("%Y-%m-%dT%H:%M:%S")

    per_hari = {}
    dilewat_lama = 0
    for d in docs:
        akun = AKUN.get(d.get("accountId"))
        if not akun or d.get("status") != "pending" or d.get("_id") in id_anak:
            continue
        iso = d.get("scheduleAt") or ""
        if iso <= batas or iso >= "2090":
            continue
        if (d.get("createdAt") or "")[:10] < a.sejak:
            dilewat_lama += 1
            continue
        t = datetime.datetime.fromisoformat(iso.replace("Z", "+00:00")).astimezone(WIB)
        if not (hari_ini <= t.date() <= akhir):
            continue
        per_hari.setdefault((akun, t.date()), []).append(d)

    akan_hold = []
    for (akun, tgl), daftar in sorted(per_hari.items()):
        if len(daftar) < 2:
            continue
        daftar.sort(key=skor)
        simpan = daftar[0]
        for d in daftar[1:]:
            if anak_per_induk.get(d.get("_id")):
                continue  # punya anak-reply: jangan dipindah
            akan_hold.append((akun, tgl, d, simpan))

    print(f"jaga 1 post/hari Threads — jendela {hari_ini}..{akhir}, dibuat sejak {a.sejak}")
    print(f"  {sum(len(v) for v in per_hari.values())} postingan diperiksa "
          f"({dilewat_lama} jadwal lama tidak disentuh)")
    if not akan_hold:
        print("  ✅ tidak ada hari dengan lebih dari 1 postingan — tidak ada yang perlu di-HOLD")
        return
    for akun, tgl, d, simpan in akan_hold:
        jd = (d.get("title") or (d.get("description") or "")[:40]).replace("\n", " ")
        print(f"  HOLD {akun} {tgl} {d.get('scheduleAt','')[11:16]}Z | {jd} "
              f"(disisakan: {(simpan.get('description') or '')[:40]!r})")
    if not a.go:
        print("\n(dry-run — pakai --go untuk memindahkan ke tayang 2099)")
        return

    c = get_client()
    log = []
    if os.path.exists(OUT):
        try:
            log = json.load(open(OUT)) or []
        except Exception:
            log = []
    gagal = 0
    for akun, tgl, d, simpan in akan_hold:
        sid = d.get("_id")
        try:
            c.update_schedule(sid, {"scheduleAt": HOLD})
        except Exception as e:
            print(f"  ❌ {sid}: {str(e)[:120]}")
            gagal += 1
            continue
        time.sleep(1)
        d2 = c.get_schedule(sid)
        if isinstance(d2, dict) and "docs" in d2:
            d2 = d2["docs"][0]
        d2 = (d2.get("data") or d2) if isinstance(d2, dict) else {}
        ok = (d2.get("scheduleAt") or "").startswith("2099")
        print(f"  {'✅' if ok else '⚠️'} {sid} {akun} {tgl} → {d2.get('scheduleAt')}")
        log.append({"tanggal_hold": str(datetime.datetime.now(WIB)),
                    "akun": akun, "tgl_awal": str(tgl), "id": sid,
                    "judul": d.get("title") or "", "disisakan": simpan.get("_id")})
    json.dump(log, open(OUT, "w"), indent=1)
    print(f"\nselesai: {len(akan_hold) - gagal} dipindah ke 2099, {gagal} gagal, log: {OUT}")


if __name__ == "__main__":
    main()
