#!/usr/bin/env python3
"""TSLaw 13 Okt 2026 — perbaikan #3566 (biaya-jasa-law-firm-surabaya).

Prioritas 2: artikel 875 kata dipanjangkan menjadi 1.000+ kata dengan isi yang benar-benar berguna.
Dry run secara default; pakai --apply untuk menulis lewat REST API (JSON, bukan XML-RPC).
"""
import base64, json, re, sys, time, urllib.request, urllib.error, importlib.util, os

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
DIR = f"{WS}/tslaw_pemulihan/perbaikan_20261013"
POST_ID = 3566
APPLY = "--apply" in sys.argv
os.makedirs(DIR, exist_ok=True)

spec = importlib.util.spec_from_file_location("cfg_tslaw", f"{WS}/cfg_tslaw.py")
m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
AUTH = base64.b64encode(f'{m.CFG["user"]}:{m.CFG["pass"]}'.encode()).decode()
BASE = f'https://{m.CFG["domain"]}'
HDR = {"Authorization": f"Basic {AUTH}", "User-Agent": "Mozilla/5.0"}


def api(path, data=None, method=None):
    r = urllib.request.Request(f"{BASE}{path}", data=json.dumps(data).encode() if data else None,
                               headers={**HDR, "Content-Type": "application/json"}, method=method)
    for i in range(3):
        try:
            with urllib.request.urlopen(r, timeout=180) as x:
                return x.status, json.loads(x.read())
        except urllib.error.HTTPError as e:
            return e.code, e.read()[:300].decode("utf-8", "replace")
        except Exception as e:
            time.sleep(4)
    return 0, "timeout"


def kata(html):
    return len(re.sub(r"<[^>]+>", " ", html).split())


# ---------------------------------------------------------------- 1. tarik versi sekarang
st, post = api(f"/wp-json/wp/v2/posts/{POST_ID}?context=edit")
assert st == 200, f"gagal tarik post: {st} {post}"
raw = post["content"]["raw"]
meta = post["meta"]
judul_lama = post["title"]["raw"]
slug_lama = post["slug"]
link_lama = post["link"]
open(f"{DIR}/post_{POST_ID}_SEBELUM.html", "w").write(raw)
json.dump(post, open(f"{DIR}/post_{POST_ID}_SEBELUM.json", "w"), ensure_ascii=False, indent=1)
print(f"# {POST_ID} | {judul_lama}")
print(f"  slug   : {slug_lama}")
print(f"  fokus  : {meta.get('_yoast_wpseo_focuskw')}")
print(f"  kata   : {kata(raw)}  | H2 {len(re.findall(r'<h2', raw))} | H3 {len(re.findall(r'<h3', raw))}")

# ---------------------------------------------------------------- 2. bagian baru
A = """<h2>Honorarium Advokat Menurut Undang-Undang</h2>

<p>Bagian yang dibayarkan ke kantor hukum disebut honorarium. Dasar hukumnya tegas: Pasal 21 ayat (1)
Undang-Undang Nomor 18 Tahun 2003 tentang Advokat menyebutkan advokat berhak menerima honorarium atas jasa
hukum yang telah diberikan kepada kliennya. Pada ayat (2) dinyatakan besarnya honorarium ditetapkan secara
wajar berdasarkan persetujuan kedua belah pihak.</p>

<p>Artinya tidak ada tarif tunggal yang berlaku untuk semua kantor. Negara tidak menerbitkan daftar harga
jasa advokat, sehingga angka akhirnya lahir dari kesepakatan antara Anda dan kantor yang Anda tunjuk. Yang
dinilai bukan hanya hasil akhir, tetapi juga kewajaran perhitungannya: lingkup pekerjaan, perkiraan waktu,
dan tingkat kerumitan perkara.</p>

<p>Kesepakatan itu sebaiknya dituangkan tertulis. Untuk pekerjaan di luar pengadilan, umumnya cukup
perjanjian jasa hukum yang memuat lingkup kerja dan cara pembayaran. Untuk mewakili Anda di persidangan,
advokat memerlukan surat kuasa khusus, karena dasar perwakilan dalam berperkara mengacu pada Pasal 123 HIR
dan Pasal 147 RBg. Dua dokumen inilah yang menjadi pegangan bila muncul perbedaan tafsir di tengah
pekerjaan.</p>

<p>Satu hal lagi yang perlu Anda tahu: hak retensi. Advokat dapat menahan berkas atau dokumen perkara
sampai kewajiban yang belum dipenuhi diselesaikan. Dalam praktik dan kode etik, hak retensi diakui
sepanjang tidak merugikan kepentingan klien. Karena itu cara paling aman adalah mengatur tahapan pembayaran
secara tegas sejak awal, bukan menundanya sampai pekerjaan berjalan jauh.</p>

"""

B = """<h2>Biaya Resmi di Luar Honorarium: Panjar Perkara dan Bea Meterai</h2>

<p>Dua pos berikut sering tertukar dengan honorarium, padahal dananya tidak masuk ke kantor hukum.</p>

<p><strong>Panjar biaya perkara.</strong> Saat perkara didaftarkan ke pengadilan, Anda menyetor panjar
biaya perkara. Isinya adalah biaya pendaftaran (PNBP) sebesar Rp30.000 untuk gugatan, biaya proses atau
ATK, biaya panggilan dan relaas yang dihitung dari jumlah pihak serta jarak, sampai biaya pemberitahuan
putusan. Besarannya ditetapkan masing-masing pengadilan dan umumnya dipublikasikan di situs resminya.
Sebagai gambaran, Pengadilan Negeri Kota Cirebon Kelas 1B mencantumkan biaya proses atau ATK Rp75.000 dan
panggilan tergugat Rp60.000 untuk tiga kali pemanggilan pada perkara gugatan. Panjar bersifat titipan:
sisa biaya perkara dikembalikan sesuai perhitungan pada buku keuangan pengadilan.</p>

<p><strong>Bea meterai.</strong> Surat perjanjian termasuk dokumen yang dikenai bea meterai. Sejak
1 Januari 2021 tarifnya Rp10.000 dan dikenakan satu kali untuk setiap dokumen, sesuai Undang-Undang Nomor
10 Tahun 2020 tentang Bea Meterai. Nilainya kecil, tetapi sering menjadi selisih di akhir pekerjaan bila
tidak disebut sejak awal.</p>

<p>Karena itu, saat membandingkan penawaran dari beberapa kantor, pisahkan tiga kolom: honorarium, biaya
resmi, dan biaya pihak ketiga. Penawaran yang tampak paling murah bisa berubah menjadi paling mahal setelah
biaya resmi dan biaya pengurusan ikut dihitung.</p>

"""

C = """<h2>Rincian yang Sebaiknya Ada dalam Penawaran Tertulis</h2>

<p>Penawaran yang baik dapat dibaca sekali lalu dipahami. Minimal enam hal ini sebaiknya tercantum di
dalamnya:</p>

<ul>
<li><strong>Lingkup pekerjaan.</strong> Apa yang dikerjakan dan apa yang tidak, termasuk batas jumlah
dokumen atau jadwal sidang yang tercakup.</li>
<li><strong>Dasar perhitungan honorarium.</strong> Tarif per jam, tarif tetap per perkara, retainer
bulanan, atau kombinasi di antaranya.</li>
<li><strong>Biaya di luar honorarium.</strong> Panjar perkara, bea meterai, notaris, penerjemah,
perjalanan, dan penggandaan dokumen.</li>
<li><strong>Jadwal pembayaran.</strong> Berapa pada saat penunjukan, berapa di setiap tahap, dan bagaimana
perhitungannya bila pekerjaan berhenti di tengah jalan.</li>
<li><strong>Advokat yang menangani.</strong> Nama advokat penanggung jawab, karena pengalaman menangani
perkara sejenis berpengaruh langsung pada waktu kerja.</li>
<li><strong>Mekanisme bila perkara berkembang.</strong> Bagaimana penyesuaian biaya dihitung dan siapa
yang menyetujuinya.</li>
</ul>

<p>Bila ada poin yang masih kabur, tanyakan sebelum menandatangani, bukan sesudah tagihan masuk. Kantor
yang bekerja tertib tidak keberatan menjelaskan rinciannya.</p>

"""

FAQ_A = """<h3>Apakah besarnya honorarium advokat diatur undang-undang?</h3>
<p>Undang-undang mengatur haknya, bukan angkanya. Pasal 21 Undang-Undang Nomor 18 Tahun 2003 tentang Advokat
menyebut advokat berhak menerima honorarium atas jasa hukum yang diberikan, dan besarnya ditetapkan secara
wajar berdasarkan persetujuan kedua belah pihak. Karena itu tarif antar kantor bisa berbeda, selama
disepakati sejak awal.</p>

"""

FAQ_B = """<h3>Apakah panjar biaya perkara bisa dikembalikan?</h3>
<p>Panjar biaya perkara adalah titipan ke pengadilan, bukan pembayaran ke kantor hukum. Sisa pemakaiannya
dikembalikan sesuai perhitungan keuangan pengadilan setelah perkara selesai. Mintalah rincian pemakaian
panjar ketika perkara sudah diputus, supaya Anda tahu ke mana dana itu pergi.</p>

"""

FAQ_BARU = [
    ("Apakah besarnya honorarium advokat diatur undang-undang?",
     "Undang-undang mengatur haknya, bukan angkanya. Pasal 21 Undang-Undang Nomor 18 Tahun 2003 tentang Advokat "
     "menyebut advokat berhak menerima honorarium atas jasa hukum yang diberikan, dan besarnya ditetapkan secara "
     "wajar berdasarkan persetujuan kedua belah pihak. Karena itu tarif antar kantor bisa berbeda, selama "
     "disepakati sejak awal."),
    ("Apakah biaya konsultasi terpisah dari biaya penanganan perkara?",
     "Bergantung kebijakan kantornya. Ada yang menyediakan konsultasi awal tanpa biaya, ada yang mengenakan tarif "
     "konsultasi yang kemudian diperhitungkan sebagai bagian dari biaya penanganan bila Anda melanjutkan kerja sama."),
    ("Bisakah biaya dicicil?",
     "Sebagian kantor membuka pembayaran bertahap mengikuti tahapan pekerjaan. Sampaikan kebutuhan Anda secara "
     "terbuka, karena banyak kantor bisa menyesuaikan skema selama lingkup pekerjaannya jelas."),
    ("Apakah panjar biaya perkara bisa dikembalikan?",
     "Panjar biaya perkara adalah titipan ke pengadilan, bukan pembayaran ke kantor hukum. Sisa pemakaiannya "
     "dikembalikan sesuai perhitungan keuangan pengadilan setelah perkara selesai. Mintalah rincian pemakaian "
     "panjar ketika perkara sudah diputus, supaya Anda tahu ke mana dana itu pergi."),
    ("Apakah kantor hukum boleh menolak memberi rincian biaya?",
     "Kantor yang bekerja tertib tidak akan keberatan memberi rincian biaya. Rincian itu yang melindungi kedua "
     "belah pihak bila pekerjaan berkembang."),
]

# ---------------------------------------------------------------- 3. sisipkan (semua anchor harus unik)
def sisip(teks, anchor, tambahan, sebelum=False):
    n = teks.count(anchor)
    assert n == 1, f"anchor tidak unik ({n}x): {anchor[:60]}"
    return teks.replace(anchor, (tambahan + anchor) if sebelum else (anchor + "\n" + tambahan))


ANCHOR_A = "bukan menjanjikan kemenangan.</p>"
ANCHOR_B = "sebaiknya dibuat dengan angka yang jelas di depan mata.</p>"
ANCHOR_C = '<h2>Pertanyaan yang Sering Diajukan</h2>'
ANCHOR_FAQ1 = "<h3>Apakah biaya konsultasi terpisah dari biaya penanganan perkara?</h3>"
ANCHOR_FAQ2 = "<h3>Apakah kantor hukum boleh menolak memberi rincian biaya?</h3>"
TAUTAN_MATI = "https://www.tslaw.id/7-hal-penting-tentang-biaya-konsultasi-hukum-yang-perlu-anda-ketahui/"
TAUTAN_HIDUP = "https://www.tslaw.id/7-hal-penting-tentang-biaya-konsultasi-hukum-yang-perlu-anda-tahu-sebelum-ke-pengacara/"

baru = sisip(raw, ANCHOR_A, A)
baru = sisip(baru, ANCHOR_B, B)
baru = sisip(baru, ANCHOR_C, C, sebelum=True)
baru = sisip(baru, ANCHOR_FAQ1, FAQ_A, sebelum=True)
baru = sisip(baru, ANCHOR_FAQ2, FAQ_B, sebelum=True)
assert baru.count(TAUTAN_MATI) == 1, "tautan mati tidak ditemukan tepat sekali"
baru = baru.replace(TAUTAN_MATI, TAUTAN_HIDUP)

# ---------------------------------------------------------------- 4. skema FAQPage diselaraskan
pola_skema = re.compile(r'<script type="application/ld\+json">\s*(\{.*?"FAQPage".*?\})\s*</script>', re.S)
mm = list(pola_skema.finditer(baru))
assert len(mm) == 1, f"blok skema FAQPage tidak tunggal: {len(mm)}"
lama_skema = json.loads(mm[0].group(1))
print(f"\nskema sebelum: {len(lama_skema['mainEntity'])} item")
tanya_jawab = FAQ_BARU
# pastikan tiap pertanyaan memang tampil di isi
for q, a in tanya_jawab:
    assert q in baru, f"pertanyaan skema tidak tampil di isi: {q}"
skema_baru = {"@context": "https://schema.org", "@type": "FAQPage",
              "mainEntity": [{"@type": "Question", "name": q,
                              "acceptedAnswer": {"@type": "Answer", "text": a}} for q, a in tanya_jawab]}
baru = baru.replace(mm[0].group(0),
                    '<script type="application/ld+json">\n' + json.dumps(skema_baru, ensure_ascii=False, separators=(",", ":")) + '\n</script>')
print(f"skema sesudah: {len(skema_baru['mainEntity'])} item, JSON valid: {bool(json.loads(json.dumps(skema_baru)))}")

# ---------------------------------------------------------------- 5. pemeriksaan
open(f"{DIR}/post_{POST_ID}_SESUDAH_dryrun.html", "w").write(baru)
nor = lambda s: re.sub(r"\s+", " ", s)
teks_lama = nor(re.sub(r"<[^>]+>", " ", re.sub(r"<script.*?</script>", " ", raw, flags=re.S)))
teks_baru = nor(re.sub(r"<[^>]+>", " ", re.sub(r"<script.*?</script>", " ", baru, flags=re.S)))
kalimat_lama = [s.strip() for s in re.split(r"(?<=[.!?])\s+", teks_lama) if len(s.strip()) > 25]
hilang = [s for s in kalimat_lama if s not in teks_baru]
print(f"\nkalimat lama: {len(kalimat_lama)} | hilang: {len(hilang)}")
for h in hilang[:5]:
    print("   HILANG ->", h[:110])
print(f"kata : {kata(raw)} -> {kata(baru)}")
print(f"H2   : {len(re.findall(r'<h2', raw))} -> {len(re.findall(r'<h2', baru))}")
print(f"H3   : {len(re.findall(r'<h3', raw))} -> {len(re.findall(r'<h3', baru))}")
jumlah_faq = len(re.findall(r"<h3>[^<]*\?</h3>", baru))
print(f"FAQ  : {jumlah_faq} pertanyaan tampil di H3")
print(f"WA   : {baru.count('wa.me/6281909222026')} | pilar /law-firm-surabaya/: {baru.count('/law-firm-surabaya/')}")
print(f"sisa tautan mati: {baru.count('yang-perlu-anda-ketahui')}")
for pola, nama in [(r"—", "em dash"), (r"[“”‘’]", "kutip melengkung"), (r"[\u4e00-\u9fff]", "CJK")]:
    c = len(re.findall(pola, baru))
    print(f"{nama}: {c}")

if not APPLY:
    print("\nDRY RUN. Jalankan dengan --apply untuk menulis.")
    sys.exit(0)

# ---------------------------------------------------------------- 6. tulis lewat REST + baca ulang
st, resp = api(f"/wp-json/wp/v2/posts/{POST_ID}", {"content": baru})
print(f"\nPOST -> {st}")
json.dump(resp if isinstance(resp, dict) else {"resp": resp}, open(f"{DIR}/post_{POST_ID}_POSTRESP.json", "w"), ensure_ascii=False, indent=1)
assert st == 200, f"penulisan gagal: {resp}"
time.sleep(2)
st2, cek = api(f"/wp-json/wp/v2/posts/{POST_ID}?context=edit")
terbaca = cek["content"]["raw"]
open(f"{DIR}/post_{POST_ID}_SESUDAH.html", "w").write(terbaca)
hasil = {
    "isi_identik_dengan_yang_dikirim": terbaca == baru,
    "judul_tidak_berubah": cek["title"]["raw"] == judul_lama,
    "slug_tidak_berubah": cek["slug"] == slug_lama,
    "fokus_tidak_berubah": cek["meta"].get("_yoast_wpseo_focuskw") == meta.get("_yoast_wpseo_focuskw"),
    "metadesc_tidak_berubah": cek["meta"].get("_yoast_wpseo_metadesc") == meta.get("_yoast_wpseo_metadesc"),
    "kata_sebelum": kata(raw), "kata_sesudah": kata(terbaca),
    "h2": [len(re.findall(r"<h2", raw)), len(re.findall(r"<h2", terbaca))],
    "h3": [len(re.findall(r"<h3", raw)), len(re.findall(r"<h3", terbaca))],
    "wa_tombol": terbaca.count("wa.me/6281909222026"),
    "item_skema": len(json.loads(re.search(r'<script type="application/ld\+json">\s*(\{.*?"FAQPage".*?\})\s*</script>', terbaca, re.S).group(1))["mainEntity"]),
    "tautan_mati": terbaca.count("yang-perlu-anda-ketahui"),
}
json.dump(hasil, open(f"{DIR}/post_{POST_ID}_VERIFIKASI.json", "w"), ensure_ascii=False, indent=1)
print(json.dumps(hasil, ensure_ascii=False, indent=1))
