#!/usr/bin/env python3
"""TSC: selaraskan judul SEO + meta description 4 artikel prioritas dengan query nyata (GSC).
Menulis hanya meta Yoast (isi artikel tidak disentuh). Jalankan --apply untuk menyimpan."""
import base64, json, os, re, sys, time, urllib.request, urllib.error, importlib.util
from xml.sax.saxutils import escape

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
spec = importlib.util.spec_from_file_location("cfg_tsc", f"{WS}/cfg_tsc.py")
mod = importlib.util.module_from_spec(spec); spec.loader.exec_module(mod)
CFG = mod.CFG
DOM, USER, PASS = CFG["domain"], CFG["user"], CFG["pass"]
AUTH = base64.b64encode(f"{USER}:{PASS}".encode()).decode()
UA = {"User-Agent": "Mozilla/5.0"}
BACKUP = f"{WS}/tsc_pemulihan/meta_lama"
os.makedirs(BACKUP, exist_ok=True)

RENCANA = [
    {"id": 9266, "slug": "kenapa-dr-avril-the-skin-code-clinic",
     "judul": "The Skin Code Clinic: Kenapa Pasien Memilih dr. Avril",
     "meta": "Alasan pasien di Krian dan Sidoarjo memilih dr. Avril Novianto di The Skin Code Clinic: penanganan kulit dan kelamin sesuai standar medis.",
     "fokus": "the skin code clinic"},
    {"id": 1709, "slug": "klinik-dni-krian-sidoarjo",
     "judul": "DNI Clinic Krian Kini The Skin Code Clinic: Apa yang Berubah",
     "meta": "DNI Clinic Krian resmi berganti nama menjadi The Skin Code Clinic. Ini yang berubah, yang tetap sama, dan cara pasien lama melanjutkan perawatan.",
     "fokus": "dni clinic krian"},
    {"id": 8464, "slug": "the-skin-code-clinic-klinik-kulit-dan-kelamin-terbaik-di-krian",
     "judul": "The Skin Code Clinic Krian | Klinik Kulit & Kelamin",
     "meta": "Klinik kulit dan kelamin di Krian, Sidoarjo. Menangani jerawat, infeksi kulit, keluhan kelamin, sampai perawatan estetika medis bersama dokter spesialis.",
     "fokus": "klinik kulit krian"},
    {"id": 9268, "slug": "faq-dokter-kulit-krian",
     "judul": "FAQ Dokter Kulit Krian | The Skin Code Clinic",
     "meta": "Pertanyaan yang sering diajukan pasien dokter kulit di Krian: biaya konsultasi, jadwal praktik, jenis perawatan, dan cara membuat janji temu.",
     "fokus": "dokter kulit krian"},
]


def rpc(method, params=()):
    def val(v):
        if isinstance(v, bool):
            return f"<value><boolean>{1 if v else 0}</boolean></value>"
        if isinstance(v, int):
            return f"<value><int>{v}</int></value>"
        if isinstance(v, list):
            return "<value><array><data>" + "".join(val(x) for x in v) + "</data></array></value>"
        if isinstance(v, dict):
            return "<value><struct>" + "".join(f"<member><name>{escape(str(k))}</name>{val(x)}</member>"
                                               for k, x in v.items()) + "</struct></value>"
        return f"<value><string>{escape(str(v))}</string></value>"
    body = ("<?xml version=\"1.0\"?><methodCall><methodName>" + method + "</methodName><params>" +
            "".join(f"<param>{val(p)}</param>" for p in params) + "</params></methodCall>").encode()
    r = urllib.request.Request(f"https://www.{DOM}/xmlrpc.php", data=body,
                               headers={"Content-Type": "text/xml", "User-Agent": "Mozilla/5.0",
                                        "Authorization": f"Basic {AUTH}"}, method="POST")
    for _ in range(3):
        try:
            with urllib.request.urlopen(r, timeout=150) as x:
                return x.read().decode("utf-8", "replace")
        except Exception:
            time.sleep(4)
    return ""


def baris(isi, kunci):
    return [(m.group(1), m.group(2)) for m in re.finditer(
        r"<member><name>id</name><value><string>(\d+)</string></value></member>\s*"
        r"<member><name>key</name><value><string>" + re.escape(kunci) +
        r"</string></value></member>\s*<member><name>value</name><value><string>(.*?)</string>", isi, re.S)]


print("=== keadaan sekarang & rencana ===")
simpanan = {}
for r in RENCANA:
    isi = rpc("wp.getPost", [1, USER, PASS, r["id"]])
    lama = {k: baris(isi, k) for k in ("_yoast_wpseo_title", "_yoast_wpseo_metadesc", "_yoast_wpseo_focuskw")}
    simpanan[str(r["id"])] = lama
    print(f"\n   #{r['id']} /{r['slug'][:44]}")
    for k in ("_yoast_wpseo_title", "_yoast_wpseo_metadesc", "_yoast_wpseo_focuskw"):
        nilai = [v for _, v in lama[k]]
        print(f"      {k:<24} lama: {nilai[0][:70] if nilai else '(kosong)'}")
    print(f"      {'judul baru':<24} {r['judul']}  ({len(r['judul'])} char)")
    print(f"      {'meta baru':<24} {r['meta'][:80]}  ({len(r['meta'])} char)")

json.dump(simpanan, open(f"{BACKUP}/meta_artikel_lama.json", "w"), indent=1, ensure_ascii=False)
print(f"\n   salinan nilai lama: {BACKUP}/meta_artikel_lama.json")

if "--apply" not in sys.argv:
    print("\n(dry run — pakai --apply untuk menyimpan)")
    sys.exit(0)

print("\n=== menyimpan ===")
for r in RENCANA:
    isi = rpc("wp.getPost", [1, USER, PASS, r["id"]])
    for kunci, nilai in (("_yoast_wpseo_title", r["judul"]), ("_yoast_wpseo_metadesc", r["meta"]),
                         ("_yoast_wpseo_focuskw", r["fokus"])):
        rows = baris(isi, kunci)
        if not rows:
            res = rpc("wp.editPost", [1, USER, PASS, r["id"], {"custom_fields": [{"key": kunci, "value": nilai}]}])
            f = re.search(r"<name>faultString</name><value><string>(.*?)</string>", res, re.S)
            print(f"   #{r['id']} {kunci:<24} (baru) → {'GAGAL ' + f.group(1)[:40] if f else '✅'}")
        for mid, _ in rows:
            res = rpc("wp.editPost", [1, USER, PASS, r["id"], {"custom_fields": [{"id": int(mid), "key": kunci, "value": nilai}]}])
            f = re.search(r"<name>faultString</name><value><string>(.*?)</string>", res, re.S)
            print(f"   #{r['id']} {kunci:<24} id {mid} → {'GAGAL ' + f.group(1)[:40] if f else '✅'}")

print("\n=== verifikasi di halaman live ===")
time.sleep(3)
for r in RENCANA:
    url = f"https://www.{DOM}/{r['slug']}/"
    try:
        h = urllib.request.urlopen(urllib.request.Request(url + f"?v={int(time.time())}", headers=UA), timeout=90).read().decode("utf-8", "replace")
        t = re.search(r"<title>(.*?)</title>", h, re.S)
        d = re.search(r'<meta name="description" content="([^"]*)"', h)
        print(f"   {r['slug'][:44]:<46} judul: {t.group(1).strip()[:56] if t else '-'}")
        print(f"        meta: ({len(d.group(1)) if d else 0} char) {d.group(1)[:70] if d else '-'}")
    except Exception as e:
        print(f"   {r['slug']}: gagal {str(e)[:50]}")
