#!/usr/bin/env python3
"""No 3: pasang FAQ + schema FAQPage ke artikel yang sudah >=1.000 kata tapi belum punya FAQ.

Cara pakai: isi JOBS = {post_id: [(pertanyaan, jawaban), ...]} lalu jalankan dengan --apply.
Bagian FAQ disisipkan sebelum blok 'Kesimpulan'/'Baca juga' bila ada, kalau tidak ditaruh sebelum
schema/CTA di akhir. Idempoten: dilewati bila artikel sudah punya FAQPage.
"""

import base64, html, json, re, sys, time, urllib.request, urllib.error

S = "https://studiosoft.id"
AUTH = base64.b64encode(b"bambangbot:q26r RePo BVy6 pwU2 F3z7 ouyl").decode()

JOBS = {}


def api(path, data=None):
    h = {"Authorization": f"Basic {AUTH}", "User-Agent": "Mozilla/5.0"}
    body = None
    if data is not None:
        body = json.dumps(data).encode(); h["Content-Type"] = "application/json"
    r = urllib.request.Request(S + path, data=body, headers=h, method="POST" if data else "GET")
    err = None
    for _ in range(4):
        try:
            with urllib.request.urlopen(r, timeout=240) as x:
                return x.status, json.loads(x.read())
        except urllib.error.HTTPError as e:
            if e.code in (404, 500, 502, 503, 504):
                time.sleep(5); continue
            return e.code, e.read().decode()[:200]
        except Exception as e:
            err = e
            time.sleep(5)
    return 0, str(err)[:150] if err else "gagal setelah 4 percobaan"


def pasang(pid, pasangan):
    st, p = api(f"/wp-json/wp/v2/posts/{pid}?context=edit&_fields=content,title")
    if not isinstance(p, dict):
        return f"#{pid} gagal ambil konten ({st})"
    raw = p["content"]["raw"]
    if '"@type":"FAQPage"' in raw or '"@type": "FAQPage"' in raw:
        return f"#{pid} sudah punya FAQPage — skip"

    blok = "\n<h2>Pertanyaan yang sering muncul</h2>\n" + "\n".join(
        f"<h3>{q}</h3>\n<p>{a}</p>" for q, a in pasangan) + "\n"
    schema = {"@context": "https://schema.org", "@type": "FAQPage",
              "mainEntity": [{"@type": "Question", "name": q,
                              "acceptedAnswer": {"@type": "Answer", "text": a}} for q, a in pasangan]}
    m = re.search(r"\n<h2[^>]*>\s*(Kesimpulan|Baca juga|Layanan StudioSoft)", raw, re.I)
    if m:
        baru = raw[:m.start()] + blok + "\n" + '<script type="application/ld+json">' + json.dumps(schema, ensure_ascii=False) + "</script>\n" + raw[m.start():]
    else:
        baru = raw.rstrip() + "\n" + blok + '<script type="application/ld+json">' + json.dumps(schema, ensure_ascii=False) + "</script>\n"

    st2, _ = api(f"/wp-json/wp/v2/posts/{pid}", {"content": baru})
    _, chk = api(f"/wp-json/wp/v2/posts/{pid}?context=edit&_fields=content")
    isi = chk.get("content", {}).get("raw", "") if isinstance(chk, dict) else ""
    kata = len(html.unescape(re.sub(r"<[^>]+>", " ", isi)).split())
    ok = '"@type":"FAQPage"' in isi or '"@type": "FAQPage"' in isi
    return f"#{pid} POST {st2} | FAQ {'terpasang' if ok else 'GAGAL'} | {kata} kata | {html.unescape(p['title']['rendered'])[:48]}"


if __name__ == "__main__":
    if not JOBS:
        print("JOBS masih kosong — isi dulu daftar FAQ per artikel.")
        sys.exit(0)
    for pid, pasangan in sorted(JOBS.items()):
        print(f"  {len(pasangan)} Q →", pasang(pid, pasangan))
        time.sleep(0.5)
