#!/usr/bin/env python3
"""TSC: uji bentuk penulisan meta via XML-RPC (dengan id, tanpa id, lewat wp.editPost vs REST)
untuk memastikan jalurnya memang tertutup atau hanya soal format."""
import base64, json, re, 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"}


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")
    try:
        with urllib.request.urlopen(r, timeout=120) as x:
            return x.status, x.read().decode("utf-8", "replace")
    except urllib.error.HTTPError as e:
        return e.code, e.read().decode("utf-8", "replace")
    except Exception as e:
        return 0, str(e)[:120]


def pesan(isi):
    f = re.search(r"<name>faultString</name><value><string>(.*?)</string>", isi, re.S)
    k = re.search(r"<name>faultCode</name><value><int>(\d+)</int>", isi)
    if f:
        return f"fault {k.group(1) if k else '?'}: {f.group(1)[:160]}"
    return "OK: " + ("tersimpan" if "<boolean>1</boolean>" in isi else isi[:100])


print("=== 1. method dasar: apakah XML-RPC bisa membaca & menulis? ===")
st, isi = rpc("wp.getProfile", [1, USER, PASS])
print(f"   wp.getProfile → {pesan(isi)}")
st, isi = rpc("demo.sayHello")
print(f"   demo.sayHello → {pesan(isi)}")

print("\n=== 2. membaca meta beranda lewat XML-RPC ===")
st, isi = rpc("wp.getPost", [1, USER, PASS, 409])
rows = re.findall(r"<name>id</name><value><string>(\d+)</string></value></member>\s*<member><name>key</name><value><string>(_yoast[^<]*)</string></value></member>\s*<member><name>value</name><value><string>(.*?)</string>", isi, re.S)
print(f"   {len(rows)} baris meta Yoast terbaca:")
for mid, k, v in rows:
    print(f"      id {mid} {k} = {v[:60]}")

print("\n=== 3. tulis dengan id (seperti yang gagal) ===")
st, isi = rpc("wp.editPost", [1, USER, PASS, 409, {"custom_fields": [{"id": 5216, "key": "_yoast_wpseo_metadesc", "value": "Uji A."}]}])
print(f"   → {pesan(isi)}")

print("\n=== 4. tulis tanpa id (tambah baris baru) ===")
st, isi = rpc("wp.editPost", [1, USER, PASS, 409, {"custom_fields": [{"key": "_yoast_wpseo_metadesc", "value": "Uji B."}]}])
print(f"   → {pesan(isi)}")

print("\n=== 5. cek apakah nilai berubah ===")
time.sleep(2)
st, isi = rpc("wp.getPost", [1, USER, PASS, 409])
rows2 = re.findall(r"<member><name>key</name><value><string>(_yoast_wpseo_metadesc)</string></value></member>\s*<member><name>value</name><value><string>(.*?)</string>", isi, re.S)
print(f"   nilai sekarang: {[v[:40] for _, v in rows2]}")

print("\n=== 6. REST: apakah endpoint posts/pages menerima meta Yoast (uji tulis) ===")
body = json.dumps({"meta": {"_yoast_wpseo_metadesc": "Uji C lewat REST."}}).encode()
r = urllib.request.Request(f"https://{DOM}/wp-json/wp/v2/pages/409", data=body,
                           headers={"Authorization": f"Basic {AUTH}", "Content-Type": "application/json", **UA}, method="POST")
with urllib.request.urlopen(r, timeout=120) as x:
    res = json.loads(x.read())
print(f"   HTTP {x.status} | meta Yoast di respons: {'ada' if any('yoast' in k for k in (res.get('meta') or {})) else 'TIDAK terdaftar → mustahil lewat REST'}")

print("\n=== 7. Yoast REST: apakah head bisa memaksa perhitungan ulang? ===")
for jalur in ("/wp-json/yoast/v1/get_head?url=https://www.theskincodeclinic.com/",
              "/wp-json/yoast/v1/indexing/posts?limit=1"):
    try:
        r = urllib.request.Request(f"https://{DOM}{jalur}", headers=UA)
        with urllib.request.urlopen(r, timeout=90) as x:
            print(f"   {x.status} | {jalur[:60]} | {x.read()[:80]}")
    except urllib.error.HTTPError as e:
        print(f"   {e.code} | {jalur[:60]}")
    except Exception as e:
        print(f"   ERR | {jalur[:60]} ({str(e)[:40]})")
