#!/usr/bin/env python3
"""Perbaikan harian tslaw.id 2026-10-08 - post 3065
/5-layanan-jasa-hukum-surabaya-untuk-umkm-dan-perusahaan-kecil-3/

Prioritas 1: artikel punya tayangan GSC (2 tayangan, 90 hari) tetapi klik NOL,
posisi 29 untuk kueri nyata "layanan hukum surabaya" dan posisi 52 untuk
"jasa hukum bisnis". Judul H1, judul SEO, meta desc, dan fokus kw diselaraskan
ke kueri yang benar-benar dipakai orang, lalu ditambah isi yang menjawabnya.

Prioritas 3-5 sudah terpenuhi di artikel ini (FAQ + skema FAQPage, tombol WA,
tautan pilar /law-firm-surabaya/) -> dipertahankan apa adanya, tidak diubah.

Bonus integritas: paragraf "Tabel di atas menunjukkan..." menunjuk tabel yang
tidak pernah ada di halaman -> diganti daftar manfaat yang benar-benar tertulis.

Jalankan tanpa argumen = dry run. Tambah --apply untuk menulis via REST (JSON).
"""
import base64, html as htmlmod, json, os, re, sys
import urllib.request, urllib.error

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
sys.path.insert(0, WS)
from cfg_tslaw import CFG

AUTH = base64.b64encode(f"{CFG['user']}:{CFG['pass']}".encode()).decode()
BASE = "https://tslaw.id/wp-json/wp/v2"
HDR = {"Authorization": f"Basic {AUTH}", "User-Agent": "Mozilla/5.0"}

PID = 3065
OUT = f"{WS}/tslaw_pemulihan/perbaikan_20261008"
os.makedirs(OUT, exist_ok=True)
APPLY = "--apply" in sys.argv


def rest_get(path, timeout=120):
    req = urllib.request.Request(BASE + path, headers=HDR)
    with urllib.request.urlopen(req, timeout=timeout) as r:
        return json.load(r)


def rest_post(path, payload, timeout=180):
    req = urllib.request.Request(
        BASE + path, data=json.dumps(payload).encode(),
        headers={**HDR, "Content-Type": "application/json"}, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            return r.status, json.load(r)
    except urllib.error.HTTPError as e:
        return e.code, e.read().decode()[:800]


def wc(s):
    t = htmlmod.unescape(re.sub(r"<(script|style).*?</\1>", " ", s, flags=re.S))
    return len(re.sub(r"<[^>]+>", " ", t).split())


# ---------------------------------------------------------------- tarik sebelum
p = rest_get(f"/posts/{PID}?context=edit")
raw = p["content"]["raw"]
open(f"{OUT}/post_{PID}_SEBELUM.html", "w").write(raw)
json.dump(p, open(f"{OUT}/post_{PID}_SEBELUM.json", "w"), ensure_ascii=False, indent=1)
KATA_SEBELUM = wc(raw)
meta0 = p.get("meta") or {}
print(f"[sebelum] kata={KATA_SEBELUM}")
print(f"[sebelum] judul H1 = {p['title']['raw']!r}")
print(f"[sebelum] fokus     = {meta0.get('_yoast_wpseo_focuskw')!r}")
print(f"[sebelum] seo title = {meta0.get('_yoast_wpseo_title')!r}")
print(f"[sebelum] meta desc = {meta0.get('_yoast_wpseo_metadesc')!r}")
print(f"[sebelum] slug      = {p['slug']!r} (TIDAK diubah)")

# ------------------------------------------------- tingkat lanjut: judul + meta
H1_BARU = "5 Layanan Hukum Surabaya untuk UMKM dan Perusahaan Kecil"
SEO_TITLE = "Layanan Hukum Surabaya untuk UMKM: 5 Pilihan Terjangkau"
META = ("Layanan hukum Surabaya dan jasa hukum bisnis untuk UMKM: legalitas, kontrak, "
        "konsultasi, sampai pendampingan sengketa. Cek 5 layanan TSLaw di sini.")
FOKUS = "layanan hukum surabaya"

assert FOKUS in SEO_TITLE.lower(), "fokus kw harus muncul di judul SEO"
assert FOKUS in META.lower(), "fokus kw harus muncul di meta desc"
assert "jasa hukum bisnis" in META.lower(), "kueri kedua harus muncul di meta desc"
assert META.lower().startswith(FOKUS), "fokus kw harus di awal meta desc"
assert 120 <= len(META) <= 158, f"panjang meta {len(META)} di luar 120-158"
assert len(SEO_TITLE) <= 61, f"judul SEO {len(SEO_TITLE)} char (batas 61)"
print(f"\n[baru] H1        ({len(H1_BARU)}) {H1_BARU}")
print(f"[baru] SEO title ({len(SEO_TITLE)}) {SEO_TITLE}")
print(f"[baru] meta desc ({len(META)}) {META}")

# ------------------------------------------------------- sisipan isi penjawab
SISIPAN = """
<h2>Layanan Hukum Surabaya: Apa Saja yang Termasuk?</h2>
<p>Layanan hukum Surabaya umumnya mencakup lima pekerjaan yang paling sering dibutuhkan usaha kecil: mengurus legalitas, menyusun dan memeriksa kontrak, konsultasi rutin, menangani sengketa, dan mendampingi ekspansi. Firma hukum di Surabaya menawarkan paket bulanan maupun per perkara, jadi Anda bisa memilih sesuai kebutuhan dan anggaran, bukan membayar untuk hal yang belum Anda perlukan.</p>
<p>Kalau Anda mencari <strong>jasa hukum bisnis</strong>, istilah itu merujuk pada pendampingan yang menyangkut kepentingan usaha, bukan perkara pribadi. Bentuknya bisa berupa pendirian badan usaha, perjanjian kerja sama, sampai penanganan wanprestasi dengan mitra. Karena kebutuhan tiap usaha berbeda, langkah paling aman adalah mulai dari konsultasi singkat: ceritakan kondisi usaha Anda, lalu tentukan layanan mana yang benar-benar perlu diambil lebih dulu.</p>
"""

MANFAAT_BARU = """<p>Pendampingan hukum bukan sekadar "uang keluar", tetapi investasi yang memberi perlindungan nyata untuk keberlangsungan bisnis Anda. Ini manfaat yang paling terasa bagi UMKM dan perusahaan kecil:</p>
<ul>
<li><strong>Keputusan lebih tenang</strong>: Anda tahu batas aman sebelum meneken kontrak atau menggandeng mitra baru.</li>
<li><strong>Negosiasi lebih kuat</strong>: dokumen yang rapi membuat posisi Anda jelas saat berhadapan dengan supplier, penyewa, atau investor.</li>
<li><strong>Risiko ditekan sejak awal</strong>: legalitas dan perjanjian yang benar menutup celah sengketa sebelum muncul.</li>
<li><strong>Bisnis lebih kredibel</strong>: bank, investor, dan mitra besar lebih mudah menerima usaha dengan berkas hukum yang lengkap.</li>
<li><strong>Biaya lebih terkendali</strong>: konsultasi dan pencegahan hampir selalu lebih murah daripada berperkara di pengadilan.</li>
</ul>"""

KONTEN = raw

# 1) H1 di dalam konten diselaraskan dengan judul baru
LAMA_H1 = "<h1>5 Layanan Jasa Hukum Surabaya untuk UMKM dan Perusahaan Kecil</h1>"
assert KONTEN.count(LAMA_H1) == 1, "H1 lama tidak ditemukan persis sekali"
KONTEN = KONTEN.replace(LAMA_H1, f"<h1>{H1_BARU}</h1>")

# 2) sisipkan bagian penjawab kueri tepat setelah paragraf pembuka
JANGKAR_AWAL = "sejak awal.</strong></p>\n<hr>"
assert KONTEN.count(JANGKAR_AWAL) == 1, "jangkar pembuka tidak unik"
KONTEN = KONTEN.replace(JANGKAR_AWAL, "sejak awal.</strong></p>\n" + SISIPAN.strip() + "\n<hr>")

# 3) ganti paragraf yang menunjuk tabel hantu dengan daftar manfaat nyata
HANTU = ('<p>Tabel di atas menunjukkan bahwa pendampingan hukum bukan sekadar "uang keluar", '
         'tetapi investasi yang memberi perlindungan nyata untuk keberlangsungan bisnis Anda.</p>')
assert KONTEN.count(HANTU) == 1, "paragraf tabel hantu tidak ditemukan"
KONTEN = KONTEN.replace(HANTU, MANFAAT_BARU)

KATA_SESUDAH = wc(KONTEN)
print(f"\n[kata] sebelum {KATA_SEBELUM} -> sesudah {KATA_SESUDAH}")

# --------------------------------------------------------------- pemeriksa teks baru
BARU = SISIPAN + MANFAAT_BARU + "\n" + H1_BARU + "\n" + SEO_TITLE + "\n" + META
cekal = {
    "em dash": BARU.count("\u2014"),
    "kutip melengkung": len(re.findall(r"[\u2018\u2019\u201c\u201d]", BARU)),
    "CJK": len(re.findall(r"[\u3000-\u9fff]", BARU)),
    "placeholder": len(re.findall(r"\{[A-Za-z_\[0-9]+\}", BARU)),
    "frasa AI": len(re.findall(r"(Di era digital|Dalam dunia yang|Selain itu|Tak dapat dipungkiri)",
                               BARU, re.I)),
}
print("[periksa teks baru]", cekal)
assert sum(cekal.values()) == 0, "teks baru tidak lolos pemeriksa"

# integritas artikel (harus tetap utuh)
untuk_cek = {
    "tombol WA": KONTEN.count("wa.me/6281909222026"),
    "skema FAQPage": KONTEN.count("FAQPage"),
    "tautan pilar law-firm-surabaya": KONTEN.count("law-firm-surabaya"),
    "h2": len(re.findall(r"<h2", KONTEN)),
    "h3": len(re.findall(r"<h3", KONTEN)),
}
print("[utuh]", untuk_cek)
assert untuk_cek["tombol WA"] == 1 and untuk_cek["skema FAQPage"] == 1
assert untuk_cek["tautan pilar law-firm-surabaya"] == 1
# bukti tidak ada bagian lain yang tersentuh: balikkan tiga suntingan -> harus sama persis
BALIK = (KONTEN.replace(SISIPAN.strip() + "\n", "", 1)
         .replace(MANFAAT_BARU, HANTU, 1)
         .replace(f"<h1>{H1_BARU}</h1>", LAMA_H1, 1))
assert BALIK == raw, "ada perubahan di luar tiga suntingan yang direncanakan"
print("[integritas] sisa artikel identik dengan versi sebelum (3 suntingan saja)")

if not APPLY:
    open(f"{OUT}/post_{PID}_SESUDAH_dryrun.html", "w").write(KONTEN)
    print("\n[DRY RUN] tidak ada yang dikirim. Jalankan dengan --apply bila sudah benar.")
    sys.exit(0)

payload = {
    "title": H1_BARU,
    "content": KONTEN,
    "meta": {
        "_yoast_wpseo_focuskw": FOKUS,
        "_yoast_wpseo_title": SEO_TITLE,
        "_yoast_wpseo_metadesc": META,
    },
}
kode, resp = rest_post(f"/posts/{PID}", payload)
print(f"\n[POST] status {kode}")
json.dump(resp, open(f"{OUT}/post_{PID}_POSTRESP.json", "w"), ensure_ascii=False, indent=1)
if kode != 200:
    print("GAGAL:", resp)
    sys.exit(1)

# ------------------------------------------------------------- baca ulang dari API
q = rest_get(f"/posts/{PID}?context=edit")
raw2 = q["content"]["raw"]
meta2 = q.get("meta") or {}
open(f"{OUT}/post_{PID}_SESUDAH.html", "w").write(raw2)
verif = {
    "id": PID, "slug": q["slug"], "status": q["status"], "modified": q["modified"],
    "judul_h1": q["title"]["raw"], "seo_title": meta2.get("_yoast_wpseo_title"),
    "fokus_kw": meta2.get("_yoast_wpseo_focuskw"),
    "meta_desc": meta2.get("_yoast_wpseo_metadesc"),
    "kata_sebelum": KATA_SEBELUM, "kata_sesudah": wc(raw2),
    "fokus_di_meta": FOKUS in (meta2.get("_yoast_wpseo_metadesc") or "").lower(),
    "h1_baru_ada": f"<h1>{H1_BARU}</h1>" in raw2,
    "sisipan_ada": "Apa Saja yang Termasuk?" in raw2,
    "tabel_hantu_hilang": "Tabel di atas" not in raw2,
    "tombol_wa": raw2.count("wa.me/6281909222026"),
    "faqpage": raw2.count("FAQPage"),
    "tautan_pilar": raw2.count("law-firm-surabaya"),
    "em_dash_baru": 0, "kutip_melengkung_baru": 0,
}
json.dump(verif, open(f"{OUT}/post_{PID}_VERIFIKASI.json", "w"), ensure_ascii=False, indent=1)
print("[verifikasi REST]", json.dumps(verif, ensure_ascii=False, indent=1))
