#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""swap_media_colors.py — ganti media jadwal THREADS/LINKEDIN yang belum tayang
(pending) ke desain BARU: background BIRU TUA #122B63 (kartu bergantian putih:
background PUTIH + teks #122B63), layout standar baru (rata kiri, blok tengah, tanpa garis).

Perintah Bos 16 Sep 2026:
  "semua versi warna navy #0D4761 dan #1E40AF ganti dengan #122B63 — ini untuk threads
   dan LinkedIn; warna background ya" + "kalau ada yang bergantian pakai background putih,
   text #122B63" + "pastikan layout pakai yang baru ini".

Aturan (sama seperti uky_swap_square.py yang sudah terbukti 16 Sep):
  • Hanya jadwal `pending` yang diswap.
  • Media baru di-upload dengan NAMA FILE BARU → jalur fetch Repliz segar (bukan cache).
  • File lama TIDAK dihapus.
  • URL wajib 200 di KEDUA ingress funnel sebelum PUT.
  • Default DRY RUN; pakai --apply untuk eksekusi. Idempoten.

Sumber gambar (PNG, sudah dirender ulang dengan warna & layout baru):
  uky_sq_<base>.jpg      -> uky_threads_images/<base>.png        (prefix baru: uky_sq2_)
  <base>_ss.jpg          -> ss_threads_images/<base>.png         (sufiks baru: _ss2.jpg)
"""
import os
import re
import subprocess
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from PIL import Image
from repliz_client import ReplizClient, ACC, IMG_BASE_URL, IMG_DIR

WS = os.path.dirname(os.path.abspath(__file__))
INGRESS = ["103.84.155.153", "103.84.155.217"]

# akun dalam scope perintah Bos (Threads & LinkedIn)
SCOPE = {
    ACC.UKY_THREADS: "UKY_THREADS",
    ACC.STUDIOSOFT_THREADS: "SS_THREADS",
    ACC.STUDIOSOFT_LINKEDIN: "SS_LINKEDIN",
    ACC.TSLAW_THREADS: "TSLAW_THREADS",
    ACC.LEIT_THREADS: "LEIT_THREADS",
    ACC.EVERYBE_THREADS: "EVERYBE_THREADS",
    ACC.TSC_THREADS: "TSC_THREADS",
    ACC.SOTO_THREADS: "SOTO_THREADS",
    ACC.LEIT_LINKEDIN: "LEIT_LINKEDIN",
    ACC.TSLAW_LINKEDIN: "TSLAW_LINKEDIN",
    ACC.DMARK_LINKEDIN: "DMARK_LINKEDIN",
}


def fetch_all(c):
    docs, page = [], 1
    while True:
        r = c.get_schedules(page=page, limit=100)
        d = r.get("docs") or r.get("data") or []
        docs += d
        if not d or page >= (r.get("totalPages") or 1):
            break
        page += 1
    return docs


def verify(url):
    ok = True
    for ip in INGRESS:
        r = subprocess.run(
            ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "30",
             "--resolve", "mantapserver.tail3947bb.ts.net:443:%s" % ip, url],
            capture_output=True, text=True)
        code = r.stdout.strip()
        print("      %s: %s" % (ip, code))
        ok = ok and code == "200"
    return ok


def to_jpeg(png_path, out_name, quality=90):
    img = Image.open(png_path)
    if img.mode in ("RGBA", "LA", "P"):
        img = img.convert("RGB")
    out = os.path.join(IMG_DIR, out_name)
    img.save(out, "JPEG", quality=quality)
    return out


def plan_for(media_name):
    """Map nama media lama -> (png sumber, nama file baru, catatan). None kalau tidak dikenal."""
    base = media_name.rsplit(".", 1)[0]
    if base.startswith("uky_sq2_"):
        return None
    if base.startswith("uky_sq_"):
        b = re.sub(r"-\d+$", "", base[len("uky_sq_"):])
        return (os.path.join(WS, "uky_threads_images", b + ".png"),
                "uky_sq2_%s.jpg" % b)
    if base.endswith("_ss2"):
        return None
    if base.endswith("_ss") and re.match(r"^\d\d_", base):
        b = base[:-3]
        return (os.path.join(WS, "ss_threads_images", b + ".png"),
                "%s_ss2.jpg" % b)
    return None


def main():
    apply = "--apply" in sys.argv
    c = ReplizClient()
    docs = fetch_all(c)

    targets = []          # (doc, nama_lama, png, nama_baru, akun)
    unknown = {}
    for d in docs:
        aid = d.get("accountId")
        if aid not in SCOPE:
            continue
        if (d.get("status") or "").lower() != "pending":
            continue
        for m in (d.get("medias") or []):
            url = m.get("url") or ""
            name = url.rsplit("/", 1)[-1].split("?")[0]
            if not name:
                continue
            p = plan_for(name)
            if p is None:
                if name.endswith((".jpg", ".png")) and not name.startswith(("uky_sq2_",)):
                    unknown.setdefault(SCOPE[aid], set()).add(name)
                continue
            targets.append((d, name, p[0], p[1], SCOPE[aid]))

    print("Jadwal pending (Threads/LinkedIn) yang bisa diswap: %d media" % len(targets))
    by_acc = {}
    for t in targets:
        by_acc.setdefault(t[4], []).append(t)
    for a in sorted(by_acc):
        print("  %-14s %d media" % (a, len(by_acc[a])))

    if unknown:
        print("\n⚠️ media di scope tapi BELUM ada pemetaannya (perlu ditangani terpisah):")
        for a in sorted(unknown):
            for n in sorted(unknown[a]):
                print("   %-14s %s" % (a, n))

    missing = sorted({t[2] for t in targets if not os.path.exists(t[2])})
    if missing:
        print("\n❌ %d PNG sumber hilang — STOP" % len(missing))
        for m in missing:
            print("   ", m)
        return 1

    print("\n── siapkan JPG baru + verifikasi 200 di kedua ingress ──")
    urls = {}
    for _, old, png, new, _acc in targets:
        path = os.path.join(IMG_DIR, new)
        if not os.path.exists(path):
            to_jpeg(png, new)
        url = "%s/openclaw-img/%s" % (IMG_BASE_URL, new)
        if url not in urls:
            print("  %s (%d bytes)" % (new, os.path.getsize(path)))
            if not verify(url):
                print("❌ %s tidak 200 di semua ingress — STOP" % new)
                return 1
            urls[url] = new

    if not apply:
        uniq = len({t[3] for t in targets})
        print("\n🧪 DRY RUN — %d jadwal, %d file baru siap. Tambahkan --apply untuk PUT."
              % (len(targets), uniq))
        return 0

    print("\n── PUT media ke %d jadwal ──" % len(targets))
    ok = 0
    for d, old, png, new, acc in targets:
        url = "%s/openclaw-img/%s" % (IMG_BASE_URL, new)
        medias = [{"type": "image", "url": url, "alt": new}]
        payload = {
            "accountId": d.get("accountId"),
            "title": d.get("title") or "",
            "description": d.get("description") or "",
            "topic": d.get("topic") or "",
            "type": d.get("type") or "image",
            "medias": medias,
            "scheduleAt": d.get("scheduleAt"),
            "replies": d.get("replies") or [],
        }
        try:
            c._request("PUT", "/public/schedule/%s" % d["_id"], payload)
            ok += 1
            print("  ✅ %s %s → %s" % (acc, d.get("scheduleAt"), new))
        except Exception as e:
            print("  ❌ %s %s: %s" % (acc, d.get("scheduleAt"), str(e)[:140]))

    print("\n── verifikasi ULANG dari API ──")
    docs2 = {x.get("_id"): x for x in fetch_all(c)}
    good = 0
    for d, old, png, new, acc in targets:
        x = docs2.get(d["_id"]) or {}
        got = [m.get("url", "").rsplit("/", 1)[-1] for m in (x.get("medias") or [])]
        g = got == [new]
        good += bool(g)
        if not g:
            print("  ⚠️ %s %s status=%s media=%s" % (acc, x.get("scheduleAt"), x.get("status"), got))
    print("\n%d/%d jadwal terverifikasi memakai media baru." % (good, len(targets)))
    return 0 if good == len(targets) else 1


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