#!/usr/bin/env python3
"""DAILY IMAGE POSTING — cron 2026-09-13T18:00Z (= 14 Sep 2026 01:00 WIB)
Item index 43: uky_thread_13_orange_website.png (brand ukyhandoko) → Threads @ukyhandoko.

Tema gambar (hasil vision, slide 3/6 dari seri @ukyhandoko):
Judul: "Jangan Bangun Website Kalau Cuma Buat 'Punya'"
Isi:  "Website bukan pajangan. Bukan portofolio yang didiemin. Website adalah mesin
      marketing 24 jam. Kalau gak ada strategi konten, SEO, dan optimasi konversi —
      mending gak usah bikin. Lebih hemat duit dan tenaga."
Footer: studiosoft.id • Digital Growth Partner

Aturan: Threads ≤500 char, gaya personal "saya", 3 paragraf, pancingan diskusi
(diskusi_engine, industri=seo, bobot 60/25/15), 0 hashtag, 0 mention internal, replies=[].
"""
import json, os, re, sys, subprocess
from datetime import datetime, timezone, timedelta

sys.path.insert(0, "/home/mantapman/.hermes/profiles/atun/workspace")
from repliz_client import get_client, ACC, IMG_BASE_URL, IMG_DIR
from PIL import Image
from diskusi_engine import ambil_pancingan, PANCINGAN

ROOT = "/home/mantapman/.hermes/profiles/atun/workspace"
ITEM_ID = "uky_thread_13_orange_website"
FILENAME = "13_orange_website.png"
SRC = os.path.join(ROOT, "uky_threads_images", FILENAME)
SLOT_UTC = "2026-10-04T01:00:00.000Z"   # 4 Okt 2026 08:00 WIB (slot 08:00 WIB bebas pertama)
SLOT_NOTE = ("08:00 WIB terisi pipeline lain s/d 3 Okt (14-17 Sep pipeline lain, 18-22 Sep=image 05-09, "
             "23-29 Sep=artikel, 30 Sep & 1 Okt=uky_quote 06/16, 2 Okt=artikel, 3 Okt=image 12) "
             "→ slot bebas 08:00 WIB pertama = 4 Okt")
UKY_T = ACC.UKY_THREADS
TITLE = "Jangan Bangun Website Kalau Cuma Buat Punya"
TOPIC = "Website = mesin marketing 24 jam, bukan pajangan"
EXPECTED_BASENAME = FILENAME.rsplit(".", 1)[0].lower() + ".jpg"

# CTA yang sudah dipakai 2 hari terakhir (jangan diulang)
CTA_EXCLUDE = {
    "Berapa lama Anda bertahan sebelum melihat hasil dari digital marketing? Share pengalamannya.",
}

BODY = (
    "Website bukan pajangan. Bukan portofolio yang didiemin. 📌\n\n"
    "Saya sering ketemu bisnis yang website-nya bagus, tapi setahun nggak diurus. "
    "Padahal website itu mesin marketing yang kerja 24 jam — kalau di dalamnya ada "
    "strategi konten, SEO, dan optimasi konversi.\n\n"
    "Kalau cuma dibikin biar \"punya\", mending nggak usah. Lebih hemat duit dan tenaga."
)

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


def build_caption():
    """Body + pancingan diskusi (tone weighted 60/25/15).

    Pancingan tone 'sanjungan' tidak selalu memuat ajakan komentar → undi beberapa kali,
    pakai pancingan pertama yang memuat CTA & belum dipakai hari sebelumnya.
    """
    for _ in range(20):
        hook = ambil_pancingan(industri="seo", tone=None)
        cap = BODY + "\n\n" + hook
        if len(cap) <= 500 and CTA_RE.search(hook) and hook not in CTA_EXCLUDE:
            return cap
    kandidat = [s for t in ("netral", "opini", "sanjungan")
                for s in PANCINGAN["seo"][t]
                if CTA_RE.search(s) and s not in CTA_EXCLUDE]
    for s in sorted(kandidat, key=len):
        if len(BODY) + len(s) + 2 <= 500:
            return BODY + "\n\n" + s
    raise SystemExit("❌ tidak ada pancingan yang muat")


def upload():
    """PNG → JPEG di openclaw-img, return URL publik."""
    os.makedirs(IMG_DIR, exist_ok=True)
    img = Image.open(SRC)
    if img.mode in ("RGBA", "LA", "P"):
        img = img.convert("RGB")
    out = os.path.join(IMG_DIR, FILENAME.rsplit(".", 1)[0] + ".jpg")
    img.save(out, format="JPEG", quality=90)
    url = f"{IMG_BASE_URL.rstrip('/')}/openclaw-img/{os.path.basename(out)}"
    return url, out


def check_public(url):
    """Simulasi jalur INTERNET (resolve ke ingress Tailscale) — bukan tailnet-direct."""
    codes = {}
    for ip in ("103.84.155.153", "103.84.155.217"):
        r = subprocess.run(
            ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "25",
             "--resolve", f"mantapserver.tail3947bb.ts.net:443:{ip}", url],
            capture_output=True, text=True)
        codes[ip] = r.stdout.strip()
    return codes


def main():
    cap = build_caption()
    print(f"CAPTION ({len(cap)} chars):\n{cap}\n")
    assert len(cap) <= 500, f"caption {len(cap)} char > 500"
    assert not re.search(r"@\w+", cap), "ada mention!"
    assert CTA_RE.search(cap), "tidak ada pancingan diskusi"
    assert "#" not in cap, "ada hashtag (aturan: 0 hashtag untuk seri ini)"

    url, out = upload()
    print("LOCAL JPEG:", out, os.path.getsize(out), "bytes")
    print("PUBLIC URL:", url)
    codes = check_public(url)
    print("INTERNET-PATH CODES:", codes)
    if not any(c == "200" for c in codes.values()):
        print("❌ URL publik tidak 200 — STOP, jangan schedule (aturan media server).")
        return 1

    c = get_client()

    def list_uky():
        r = c.get_schedules(page=1, limit=100)
        pages = (r["totalDocs"] + 99) // 100
        docs = list(r["docs"])
        for p in range(2, pages + 1):
            docs.extend(c.get_schedules(page=p, limit=100)["docs"])
        hits = []
        for d in docs:
            acc = d.get("account") or {}
            if (d.get("accountId") or acc.get("id") or acc.get("_id")) != UKY_T:
                continue
            meds = d.get("medias") or []
            u = (meds[0].get("url") if meds else "") or ""
            # ⚠️ exact basename — substring match pernah salah cocokkan seri uky_quote_*
            if os.path.basename(u.split("?")[0]).lower() == EXPECTED_BASENAME:
                hits.append(d)
        return hits

    # ── IDEMPOTENSI (create response pakai 'scheduleId', bukan '_id') ──
    pre = list_uky()
    if pre:
        sid = pre[0].get("id")
        print(f"⏭️  sudah ada {len(pre)} jadwal utk media ini → SKIP create (id={sid})")
    else:
        res = c.create_schedule(
            UKY_T, cap, SLOT_UTC,
            title=TITLE, topic=TOPIC,
            type_="image",
            medias=[{"url": url, "type": "image", "alt": FILENAME}],
            replies=[],
        )
        sid = res.get("scheduleId") or res.get("_id") or res.get("id")
        print("CREATE RESPONSE:", json.dumps(res)[:400])
    print("SID:", sid)

    # ── VERIFIKASI via re-list (jangan percaya response create) ──
    hits = list_uky()
    print(f"\nVERIFIKASI: {len(hits)} jadwal 13_orange_website di Threads uky")
    ok = False
    for d in hits:
        wib = datetime.fromisoformat(d["scheduleAt"].replace("Z", "+00:00")) + timedelta(hours=7)
        print(f"  id={d.get('id')} status={d.get('status')} type={d.get('type')} at={wib.strftime('%Y-%m-%d %H:%M')} WIB")
        print(f"  media={d['medias'][0]['url']}")
        print(f"  desc({len(d.get('description') or '')}) replies={len(d.get('replies') or [])}")
        if d.get("id") == sid and d.get("status") == "pending":
            ok = True
    if not (ok and len(hits) == 1):
        print("⚠️ verifikasi tidak pas (harus 1 pending dgn sid cocok) → state TIDAK dimajukan")
        return 1
    print("\n✅ TERVERIFIKASI: 1 jadwal pending, media + caption terpasang")

    # ── UPDATE STATE + LOG ──
    sp = os.path.join(ROOT, "image_posting_state.json")
    st = json.load(open(sp))
    st["index"] = (st["index"] + 1) % st["total"]
    json.dump(st, open(sp, "w"), indent=2)
    print("STATE →", st)

    lp = os.path.join(ROOT, "image_posting_log.json")
    log = json.load(open(lp))
    log.append({
        "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
        "item_id": ITEM_ID, "brand": "ukyhandoko", "source": "uky_threads_images",
        "filename": FILENAME, "topic": TOPIC,
        "slot_note": SLOT_NOTE,
        "schedule_times": {"threads_uky": SLOT_UTC + " (08:00 WIB 2026-10-04) - image 1"},
        "repliz_ids": {"threads_uky": sid},
        "caption_chars": len(cap), "media_url": url,
        "caption_final": cap,
        "next_index": st["index"],
    })
    json.dump(log, open(lp, "w"), indent=2, ensure_ascii=False)
    print("LOG →", lp, f"({len(log)} entri)")
    return 0


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