#!/usr/bin/env python3
"""SEBAR LINK studiosoft.id ke channel yang masih NGANGGUR.

Target (2 channel, 1 post/hari masing-masing):
  - FACEBOOK StudioSoft   (6a334952c5ff4ce3a3225941) type=text, replies=[]  <- gambar distop 15 Sep, sekarang 0 pending
  - LINKEDIN pribadi Uky  (6a33ca10c5ff4ce3a322705d) type=text, replies=[]  <- cuma 1 pending, mati sejak 1 Sep

Mode:
  preview [hari]  -> cetak caption + slot (TIDAK create apa pun)
  run     [hari]  -> create jadwal (idempoten: link sama di akun sama = skip)

Aturan yang dipegang: link WAJIB dari studiosoft.id, hashtag huruf kecil,
0 mention antar akun kita, ada ajakan diskusi, replies=[] (FB & LinkedIn tidak
support replies -> error 'postId').
"""
import json
import os
import sys
from datetime import datetime, timedelta, timezone

from repliz_client import get_client, ReplizError

WIB = timezone(timedelta(hours=7))
SLOTS_WIB = [5, 8, 11, 14, 17, 20, 23]
STATE = "sebar_link_ss_state.json"

TARGETS = [
    {
        "key": "fb_studiosoft",
        "label": "Facebook StudioSoft",
        "account": "6a334952c5ff4ce3a3225941",
        "kind": "fb",
    },
    {
        "key": "li_uky",
        "label": "LinkedIn Uky Yanuhandoko (pribadi)",
        "account": "6a33ca10c5ff4ce3a322705d",
        "kind": "li",
    },
]


# ── Caption builders ────────────────────────────────────────────────────────

def bersih(t):
    for a, b in (("&#038;", "&"), ("&#8217;", "'"), ("&#8216;", "'"),
                 ("&#8211;", "-"), ("&#8220;", '"'), ("&#8221;", '"'),
                 ("&amp;", "&"), ("&#8230;", "...")):
        t = t.replace(a, b)
    return t.strip()


def judul_bersih(art):
    return bersih(art["title"]["rendered"]).split("|")[0].strip()


TEMA = [
    ("ai", ["ai", "otomasi", "chatbot", "automasi"], "#ai #otomasibisnis #digitalmarketing"),
    ("branding", ["branding", "creative-agency", "digital-agency", "agency"], "#branding #digitalmarketing #umkm"),
    ("lokal", ["sidoarjo", "malang", "surabaya", "seo-lokal"], "#seolokal #umkm #surabaya"),
    ("industri", ["bengkel", "maklon", "firma-hukum", "klinik", "rumah-sakit"], "#digitalmarketing #kontenbisnis #umkm"),
    ("layanan", ["retainer", "paket", "kelola-sosial"], "#digitalmarketing #umkm #bisnisonline"),
]


def tema_hashtag(art):
    slug = art["slug"].lower()
    for _nama, kunci, tag in TEMA:
        if any(k in slug for k in kunci):
            return tag
    return "#digitalmarketing #seo #umkm"


def tema_konteks(art):
    """Satu kalimat konteks audiens sesuai tema artikel."""
    slug = art["slug"].lower()
    if any(k in slug for k in ["ai", "otomasi", "chatbot", "automasi"]):
        return "Banyak pemilik bisnis sudah pakai AI, tapi cuma buat hal yang belum tentu berpengaruh ke penjualan."
    if any(k in slug for k in ["branding", "agency", "creative-agency", "digital-agency"]):
        return "Banyak bisnis tumbuh cepat di awal, lalu mentok karena brand-nya belum punya fondasi yang jelas."
    if any(k in slug for k in ["bengkel", "maklon", "firma-hukum", "klinik", "rumah-sakit"]):
        return "Bisnis di industri ini jarang masalah kualitas — yang sering kurang cuma cara menjelaskannya ke calon pelanggan."
    if any(k in slug for k in ["retainer", "paket", "kelola-sosial"]):
        return "Saya sering lihat anggaran marketing keluar tiap bulan, tapi tidak jelas hasilnya apa."
    return "Saya sering lihat pemilik usaha sudah punya website, tapi tidak pernah jadi sumber pelanggan baru."


def caption_fb(art, idx=0):
    judul = judul_bersih(art)
    link = art["link"]
    tag = tema_hashtag(art)
    konteks = tema_konteks(art)

    varian = [
        (
            f"{konteks}\n\n"
            f"Saya tulis lebih lengkap di artikel ini: {judul}. "
            f"Isinya soal penyebabnya, urutan kerja yang masuk akal, dan hal apa yang bisa Anda rapikan lebih dulu "
            f"tanpa harus ganti semuanya.\n\n"
            f"Baca di sini: {link}\n\n"
            f"Kalau di bisnis Anda, bagian mana yang paling sulit: menentukan prioritas atau mengeksekusinya? "
            f"Boleh tulis di kolom komentar, saya bantu jawab satu-satu.\n\n{tag}"
        ),
        (
            f"Pertanyaan ini sering muncul di grup pemilik bisnis: \"Saya harus mulai dari mana dulu?\"\n\n"
            f"Jawabannya biasanya tidak berawal dari iklan. Mulai dari yang bisa diukur: pastikan website Anda "
            f"benar-benar bisa ditemukan dan meyakinkan orang yang sudah datang ke sana.\n\n"
            f"Panduan lengkapnya saya tulis di artikel berikut:\n{judul}\n{link}\n\n"
            f"Anda tim 'beresin fondasi dulu' atau tim 'ngikutin tren dulu'? Cerita dong di komentar.\n\n{tag}"
        ),
        (
            f"Salah satu pelajaran yang paling sering kami ulang ke klien:\n\n"
            f"Yang menentukan bisnis ditemukan bukan seberapa sering posting, tapi seberapa jelas website "
            f"dan kontennya menjawab pertanyaan calon pelanggan.\n\n"
            f"Topik ini kami bedah di artikel: {judul}\n{link}\n\n"
            f"Menurut Anda, apa yang paling cepat mendatangkan pelanggan untuk bisnis lokal? "
            f"Tulis pengalaman Anda di komentar ya.\n\n{tag}"
        ),
    ]
    return varian[idx % len(varian)]


def caption_li(art, idx=0):
    judul = judul_bersih(art)
    link = art["link"]
    tag = tema_hashtag(art)
    konteks = tema_konteks(art)

    varian = [
        (
            f"Saya sering ditanya pemilik bisnis: \"Bang, kenapa kompetitor saya selalu muncul lebih dulu di Google?\"\n\n"
            f"Jarang sekali jawabannya soal budget iklan. Biasanya soal fondasi yang dibangun rapi dan dirawat konsisten — "
            f"dan itu yang kami kerjakan setiap hari di StudioSoft.\n\n"
            f"Salah satu topik yang kami tulis tuntas di website: {judul}.\n"
            f"Baca versi lengkapnya di sini: {link}\n\n"
            f"Saya penasaran — prioritas Anda tahun ini lebih ke mencari pelanggan baru atau merapikan yang sudah ada? "
            f"Sharing di komentar, mungkin bisa saling belajar.\n\n{tag}"
        ),
        (
            f"{konteks} Setelah 10 tahun mengerjakan ini, pola yang saya lihat selalu berulang.\n\n"
            f"Bukan yang paling besar budgetnya yang menang, tapi yang paling rapi menjalankan dasar-dasarnya: "
            f"pesan yang jelas, halaman yang meyakinkan, dan pengukuran yang jujur soal hasil.\n\n"
            f"Catatan lengkapnya saya tuangkan di artikel ini: {judul}\n{link}\n\n"
            f"Di organisasi Anda, siapa yang pegang keputusan prioritas marketing? Saya tertarik dengar "
            f"pandangan teman-teman di komentar.\n\n{tag}"
        ),
        (
            f"Kadang yang perlu diubah bukan strateginya, tapi urutan mengerjakannya.\n\n"
            f"Tim kami sering diminta mengejar hasil cepat, padahal akar masalahnya ada di hal mendasar: "
            f"website lambat, halaman tidak relevan, dan konten yang menumpuk tanpa arah.\n\n"
            f"Saya tulis kerangkanya di sini: {judul}\n{link}\n\n"
            f"Kalau boleh jujur — apa tantangan terbesar marketing di bisnis Anda saat ini? "
            f"Tulis di komentar, saya baca semuanya.\n\n{tag}"
        ),
    ]
    return varian[idx % len(varian)]


def validasi(cap, link):
    err = []
    if link not in cap:
        err.append("link hilang")
    if not any(k in cap.lower() for k in ["komentar", "menurut", "sharing", "cerita", "pengalaman", "pendapat"]):
        err.append("tanpa ajakan diskusi")
    if "@" in cap:
        err.append("ada mention")
    import re
    bad = [t for t in re.findall(r"#(\w+)", cap) if t != t.lower()]
    if bad:
        err.append(f"hashtag kapital: {bad}")
    if len(cap) > 2000:
        err.append(f"kepanjangan {len(cap)}")
    return err


# ── Slot & state ────────────────────────────────────────────────────────────

def semua_jadwal(c, account_id):
    """Fetch ULANG dari API (jangan pakai snapshot lama)."""
    out, page = [], 1
    while True:
        r = c.get_schedules(page=page, limit=100)
        docs = r.get("docs") or r.get("data") or []
        if not docs:
            break
        out.extend([d for d in docs if d.get("accountId") == account_id])
        if len(docs) < 100:
            break
        page += 1
    return out


def slot_bebas(c, account_id, sekarang=None):
    """Cari slot (tanggal, jam WIB) kosong berikutnya, 1 post/hari."""
    sekarang = sekarang or datetime.now(WIB)
    docs = semua_jadwal(c, account_id)
    terpakai = set()
    for d in docs:
        if d.get("status") not in ("pending", "draft", "processing"):
            continue
        sa = d.get("scheduleAt") or ""
        if len(sa) >= 13:
            terpakai.add(sa[:13])  # tanggal + jam (UTC)
    hari = sekarang.date()
    for _ in range(60):
        for jam in SLOTS_WIB:
            kandidat = datetime(hari.year, hari.month, hari.day, jam, 0, tzinfo=WIB)
            if kandidat <= sekarang + timedelta(minutes=30):
                continue
            kunci = kandidat.astimezone(timezone.utc).strftime("%Y-%m-%dT%H")
            if kunci in terpakai:
                continue
            return kandidat
        hari += timedelta(days=1)
    return None


def muat_state():
    if os.path.exists(STATE):
        return json.load(open(STATE))
    return {"posted": []}


def simpan_state(s):
    json.dump(s, open(STATE, "w"), indent=1, ensure_ascii=False)


def dipakai(state, key, url):
    n = url.rstrip("/").lower()
    return any(p["akun"] == key and p["url"].rstrip("/").lower() == n for p in state["posted"])


# ── Main ────────────────────────────────────────────────────────────────────

def main():
    mode = sys.argv[1] if len(sys.argv) > 1 else "preview"
    jumlah = int(sys.argv[2]) if len(sys.argv) > 2 else 5

    arts = json.load(open("/tmp/ss_articles_fresh.json"))
    state = muat_state()
    c = get_client()

    print(f"stok artikel fresh: {len(arts)} | mode: {mode}\n")
    created = 0

    for t in TARGETS:
        builder = caption_fb if t["kind"] == "fb" else caption_li
        kandidat = [a for a in arts if not dipakai(state, t["key"], a["link"])]
        print(f"=== {t['label']} — {len(kandidat)} artikel tersedia ===")
        contoh = 3 if mode == "preview" else jumlah
        for i, art in enumerate(kandidat[:contoh]):
            cap = builder(art, i)
            masalah = validasi(cap, art["link"])
            if mode == "preview":
                slot = slot_bebas(c, t["account"])
                print(f"\n--- [{i+1}] {judul_bersih(art)[:75]}")
                print(f"    slot kandidat: {slot.strftime('%Y-%m-%d %H:%M WIB') if slot else '-'} | {len(cap)} char"
                      f" | validasi: {'OK' if not masalah else masalah}")
                print("    " + cap.replace("\n", "\n    ")[:1500])
                continue
            if masalah:
                print(f"  ⚠️ SKIP (validasi): {masalah}")
                continue
            slot = slot_bebas(c, t["account"])
            if not slot:
                print("  ⚠️ tidak ada slot bebas")
                break
            payload = {
                "accountId": t["account"],
                "title": bersih(art["title"]["rendered"])[:80],
                "topic": "Artikel Website StudioSoft",
                "type": "text",
                "description": cap,
                "medias": [],
                "scheduleAt": slot.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z"),
                "replies": [],
            }
            try:
                res = c.post("/public/schedule", payload)
                sid = res.get("scheduleId") or res.get("_id") or res.get("id")
                print(f"  ✅ {slot.strftime('%d %b %H:%M WIB')} | {bersih(art['title']['rendered'])[:55]} | id={sid}")
                state["posted"].append({
                    "akun": t["key"], "url": art["link"], "id": sid,
                    "scheduleAt": payload["scheduleAt"],
                })
                simpan_state(state)
                created += 1
            except ReplizError as e:
                print(f"  ❌ gagal: {e}")
    if mode != "preview":
        print(f"\ntotal dibuat: {created}")


if __name__ == "__main__":
    try:
        main()
    except ReplizError as e:
        print("ReplizError:", e)
        sys.exit(1)
