#!/usr/bin/env python3
"""Perbaikan harian tslaw.id 2026-10-07 - post 3057
/7-alasan-mengapa-jasa-pengacara-terbaik-surabaya-wajib-untuk-kasus-bisnis-anda-3/

Prioritas 1: ada tayangan GSC (2) tetapi klik NOL, posisi 25-28 (band 11-30) untuk
kueri nyata "pengacara surabaya terbaik" dan "pengacara terbaik di surabaya".
Judul H1, judul SEO, meta desc, dan fokus kw diselaraskan ke kueri itu, lalu isi
yang menjawabnya ditambahkan.
Prioritas 2: artikel hanya 562 kata -> diperpanjang jadi 1.000+ kata berguna.
Prioritas 3: FAQ yang sudah tampil (5 tanya-jawab) tetap dipakai, skemanya dibangun
ulang dari teks yang benar-benar tampil (tidak mengarang).
Prioritas 4: tombol WA sudah ada -> hanya teks prefill yang diperbaiki (typo "ngin").
Prioritas 5: tautan pilar /law-firm-surabaya/ sudah ada tepat 1 -> dipertahankan.
Bonus integritas: H2 terpotong ("...sudah ma.", "...memberikan ."), <p> bersarang,
"TSLaw" -> "TS Law", anchor text Baca juga yang terpotong.
Dasar hukum dicek lewat Serper: UU 18/2003 Pasal 14, 17, 22; Perma 1/2016.

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 = 3057
OUT = f"{WS}/tslaw_pemulihan/perbaikan_20261007"
os.makedirs(OUT, exist_ok=True)


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())


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} judul={p['title']['raw']!r}")
print(f"[sebelum] fokus={meta0.get('_yoast_wpseo_focuskw')!r} seo={meta0.get('_yoast_wpseo_title')!r}")

# ---------------- ambil bagian yang dipertahankan apa adanya ----------------
i_div = raw.index('<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">')
i_baca = raw.index("<h2>Baca juga</h2>")
WA_ASLI = raw[i_div:i_baca]
BACA_ASLI = raw[i_baca:raw.index("<h2>Perkara Bisnis Butuh Pemahaman Ganda</h2>")]
assert WA_ASLI.count("wa.me/6281909222026") == 1, "tombol WA tidak seperti seharusnya"
assert BACA_ASLI.count("law-firm-surabaya") == 0

# perbaiki teks prefill tombol WA (salah ketik "ngin") tanpa mengubah desain
WA_BTN = WA_ASLI.replace("Hi%20TSLaw%20Saya%20ngin%20konsultasi%20hukum",
                         "Halo%20TS%20Law%2C%20saya%20ingin%20konsultasi%20soal%20kasus%20bisnis")
assert WA_BTN != WA_ASLI and WA_BTN.count("wa.me/6281909222026") == 1

# rapikan anchor text Baca juga yang terpotong (isi tetap sama)
BACA = BACA_ASLI.replace("yang Tepat untuk Ka</a>", "yang Tepat untuk Kasus Hukum Anda</a>")
assert "yang Tepat untuk Ka</a>" not in BACA

H2 = '<h2 class="wp-block-heading">%s</h2>'
H3 = '<h3 class="wp-block-heading">%s</h3>'
P = "<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->"
H2B = "<!-- wp:heading -->\n" + H2 + "\n<!-- /wp:heading -->"

BAGIAN = []

BAGIAN.append(P % ("Mencari pengacara Surabaya terbaik untuk urusan bisnis bukan soal memilih kantor "
    "yang paling besar atau paling rajin muncul di mesin pencari. Yang menentukan adalah apakah orang "
    "yang Anda tunjuk paham perkara Anda, mengerti konsekuensi bisnisnya, dan bersedia jujur soal "
    "peluang menang."))
BAGIAN.append(P % ("Salah pilih di awal biasanya baru terasa belakangan. Strategi hukum berjalan, tapi "
    "hubungan dagang rusak. Atau sebaliknya, Anda terlalu lama menahan diri sampai posisi sendiri "
    "melemah. Ulasan berikut merinci apa yang benar-benar perlu dinilai sebelum menyerahkan perkara ke "
    "sebuah kantor hukum."))

BAGIAN.append(H2B % "Kenapa Kasus Bisnis Butuh Penanganan yang Berbeda")
BAGIAN.append(P % ("Perkara yang melibatkan usaha menuntut dua pemahaman sekaligus: hukum dan bisnis. "
    "Langkah yang benar secara teori bisa merugikan secara komersial. Somasi mempercepat pembayaran, "
    "tetapi sekaligus memutus hubungan dengan mitra yang masih dibutuhkan. Gugatan memulihkan hak, "
    "tetapi menyita waktu dan perhatian pemilik usaha."))
BAGIAN.append(P % ("Pengacara yang biasa menangani perkara bisnis mempertimbangkan dampak jangka "
    "panjang, bukan hanya kemenangan di atas kertas. Mereka menghitung apakah jalur pengadilan sepadan "
    "dengan nilai sengketa, dan apakah ada cara yang lebih murah untuk mencapai hasil yang sama."))

BAGIAN.append(H2B % "7 Hal yang Perlu Dinilai Sebelum Menunjuk Pengacara")

BAGIAN.append(H3 % "1. Status dan izin praktik")
BAGIAN.append(P % ("Setiap advokat yang berpraktik harus lulus ujian, diambil sumpah, dan memegang "
    "Kartu Tanda Anggota (KTA) dari organisasi advokat. Dua dokumen itu yang membedakan advokat dari "
    "orang yang sekadar mengaku konsultan hukum. Saat konsultasi pertama, wajar saja kalau Anda "
    "menanyakan nomor KTA atau memastikan nama advokatnya benar-benar terdaftar."))

BAGIAN.append(H3 % "2. Rekam jejak pada jenis perkara yang sama")
BAGIAN.append(P % ("Tanyakan perkara apa saja yang pernah mereka tangani yang mirip dengan perkara "
    "Anda, bukan sekadar berapa banyak perkara yang pernah dimenangkan. Kantor yang biasa menangani "
    "sengketa kontrak dagang punya insting berbeda dari kantor yang sehari-hari menangani pertanahan "
    "atau perceraian. Minta contoh konkret: wanprestasi, kepailitan, atau sengketa ketenagakerjaan."))

BAGIAN.append(H3 % "3. Kekuatan di litigasi dan non-litigasi")
BAGIAN.append(P % ("Sebagian kantor kuat di ruang sidang, sebagian lain lebih kuat di meja "
    "perundingan. Perkara bisnis sering menuntut keduanya. Kalau sengketa Anda berpotensi berujung ke "
    "pengadilan, pastikan kantornya memang biasa beracara. Sebaliknya, untuk penyusunan dan telaah "
    "kontrak, kemampuan negosiasi lebih menentukan daripada jam terbang di persidangan."))

BAGIAN.append(H3 % "4. Keterbukaan soal risiko")
BAGIAN.append(P % ("Waspadai pengacara yang menjanjikan kemenangan sebelum membaca dokumen Anda. "
    "Penilaian yang jujur biasanya memuat tiga hal: apa yang kuat dari posisi Anda, apa yang lemah, dan "
    "apa yang perlu disiapkan untuk menutup kelemahan itu. Advokat yang baik menjelaskan kemungkinan "
    "hasil terburuk, bukan hanya yang terbaik."))

BAGIAN.append(H3 % "5. Kejelasan pola biaya")
BAGIAN.append(P % ("Model pembayaran advokat lazimnya tiga: honorarium per perkara, retainer bulanan "
    "untuk pendampingan berkelanjutan, dan tarif yang dikaitkan dengan hasil. Sebelum menandatangani "
    "apa pun, minta rincian tertulis: apa saja yang sudah termasuk, apa yang dihitung terpisah, dan "
    "seberapa sering tagihan diterbitkan. Rincian komponen biaya dan cara menekannya dibahas di artikel "
    '<a href="https://www.tslaw.id/biaya-jasa-law-firm-surabaya/">biaya jasa law firm Surabaya</a>.'))

BAGIAN.append(H3 % "6. Siapa yang benar-benar mengerjakan perkara")
BAGIAN.append(P % ("Di kantor yang besar, nama yang Anda temui saat konsultasi belum tentu yang "
    "mengurus berkas sehari-hari. Ada associate dan paralegal di belakangnya, dan itu tidak selalu "
    "buruk. Tanyakan siapa penanggung jawab perkara Anda dan seberapa sering dia akan memberi kabar. "
    "Kejelasan sejak awal mengurangi kejutan di tengah jalan."))

BAGIAN.append(H3 % "7. Kecepatan merespons")
BAGIAN.append(P % ("Sengketa bisnis punya tenggat yang tidak bisa ditawar: masa berlaku somasi, batas "
    "waktu pengajuan gugatan, sampai jadwal mediasi. Kantor yang lambat membalas pesan bisa membuat "
    "Anda kehilangan momentum. Ujian paling sederhana adalah kecepatan respons saat Anda menghubungi "
    "pertama kali."))

BAGIAN.append(H2B % "Jalur Non-Litigasi yang Sebaiknya Dicoba Lebih Dulu")
BAGIAN.append(P % ("Tidak setiap sengketa harus berakhir di pengadilan. Untuk sengketa perdata yang "
    "diperiksa di pengadilan, mediasi justru wajib ditempuh lebih dulu menurut Peraturan Mahkamah Agung "
    "Nomor 1 Tahun 2016 tentang Prosedur Mediasi di Pengadilan. Kalau mediasi menghasilkan kesepakatan, "
    "kesepakatan itu dituangkan dalam akta perdamaian yang mengikat kedua pihak. Gagal mediasi, perkara "
    "dilanjutkan ke pemeriksaan pokok."))
BAGIAN.append(P % ("Di luar pengadilan ada negosiasi langsung dan arbitrase lewat lembaga seperti BANI, "
    "asalkan kontrak Anda mencantumkannya. Jalur-jalur ini biasanya lebih cepat dan menjaga "
    "kerahasiaan, dua hal yang sering penting bagi perusahaan."))

BAGIAN.append(H2B % "Dokumen yang Perlu Anda Siapkan Sebelum Konsultasi")
BAGIAN.append("""<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>Kronologi kejadian, ditulis urut tanggal.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Kontrak atau perjanjian yang menjadi dasar sengketa, termasuk lampiran dan surat-menyurat.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Bukti komunikasi: surel, pesan, notulen rapat.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Bukti transaksi: faktur, kuitansi, mutasi rekening.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Dokumen legalitas usaha bila perkara menyangkut perusahaan.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->""")
BAGIAN.append(P % ("Berkas yang rapi pada konsultasi pertama memangkas waktu yang dibutuhkan untuk "
    "membaca perkara. Waktu yang terpangkas itu biasanya ikut memangkas biaya."))

BAGIAN.append(H2B % "Apa yang Bisa Anda Harapkan dari Advokat yang Tepat")
BAGIAN.append(P % ("Undang-Undang Nomor 18 Tahun 2003 tentang Advokat memberi kerangka yang cukup "
    "jelas. Pasal 17 memberi advokat hak memperoleh informasi, data, dan dokumen dari instansi "
    "pemerintah maupun pihak lain yang berkaitan dengan perkara, sehingga ada dasar bagi mereka untuk "
    "mengurus dokumen yang sulit Anda akses sendiri. Pasal 14 menjamin advokat bebas mengeluarkan "
    "pendapat dalam membela perkara yang menjadi tanggung jawabnya di sidang pengadilan, dengan tetap "
    "tunduk pada kode etik profesi."))
BAGIAN.append(P % ("Pasal 22 ayat (1) mewajibkan advokat memberi bantuan hukum secara cuma-cuma "
    "kepada pencari keadilan yang tidak mampu. Untuk perkara bisnis ketentuan ini jarang dipakai, tapi "
    "berguna sebagai penanda kantor yang menaati standar profesinya. Kantor yang serius juga menjelaskan "
    "lingkup pekerjaan secara tertulis sejak awal, bukan setelah tagihan keluar."))

BAGIAN.append(H2B % "Kesalahan Umum saat Memilih Pengacara untuk Bisnis")
BAGIAN.append("""<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>Memilih karena kedekatan pribadi, bukan karena keahliannya cocok dengan perkara.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Menunda konsultasi sampai sengketa membesar, padahal banyak masalah bisa dicegah di tahap kontrak.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Tidak menanyakan siapa penanggung jawab perkara dan bagaimana kabar akan disampaikan.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Tidak meminta lingkup pekerjaan tertulis, sehingga muncul biaya yang tidak terduga di akhir.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Mengambil keputusan hukum saat emosi, misalnya langsung menggugat padahal nilai sengketa lebih kecil dari biaya berperkara.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->""")

BAGIAN.append(H2B % "Kesimpulan")
BAGIAN.append(P % ("Pengacara Surabaya terbaik untuk kasus bisnis bukan yang paling banyak disebut di "
    "mesin pencari, melainkan yang cocok dengan perkara Anda. Periksa izin praktiknya, minta contoh "
    "perkara sejenis, uji keterbukaannya soal risiko, dan pastikan pola biayanya jelas sejak awal. "
    "Empat hal itu saja sudah menyaring sebagian besar kesalahan pemilihan."))
BAGIAN.append(P % ("Kalau perkara Anda menyangkut sengketa dagang atau kebutuhan legalitas perusahaan, "
    "menghubungi kantor yang sehari-hari menangani perkara bisnis sejak awal lebih hemat daripada "
    "memperbaiki kesalahan di tengah jalan."))

# ---------------- FAQ: pertanyaan yang sudah tampil di halaman ----------------
FAQ = [
    ["Kapan usaha butuh jasa pengacara?",
     "Minimal pada tiga titik: saat menyusun atau meninjau kontrak bernilai besar, saat menghadapi "
     "sengketa dengan mitra atau pelanggan, dan saat melakukan restrukturisasi usaha. Meminta "
     "pendampingan di tahap pencegahan biasanya lebih murah daripada berperkara."],
    ["Apakah harus sampai pengadilan?",
     "Tidak selalu. Untuk sengketa perdata, mediasi wajib ditempuh lebih dulu menurut Perma Nomor 1 "
     "Tahun 2016. Kalau mediasi bersepakat, perkara selesai lewat akta perdamaian. Negosiasi langsung "
     "dan arbitrase juga sering lebih menguntungkan, terutama bila hubungan dagang ingin dijaga."],
    ["Berapa biaya jasa hukum perusahaan?",
     "Bervariasi, tergantung lingkup dan nilai perkara. Umumnya ada skema honorarium per perkara dan "
     "retainer bulanan untuk pendampingan berkelanjutan. Rincian komponennya dibahas di artikel biaya "
     "jasa law firm Surabaya."],
    ["Apakah bisa memakai jasa hanya untuk sesi konsultasi?",
     "Bisa. Banyak kantor membuka konsultasi terbatas tanpa melanjutkan ke pendampingan penuh. Pastikan "
     "sejak awal apa yang tercakup dalam sesi itu supaya hasilnya bisa Anda pakai."],
    ["Apa yang perlu disiapkan?",
     "Kronologi kejadian urut tanggal, kontrak yang jadi dasar sengketa, bukti komunikasi dan "
     "transaksi, serta dokumen legalitas usaha bila perkara menyangkut perusahaan."],
]

BAGIAN_FAQ = ['<h2>Pertanyaan yang Sering Diajukan</h2>']
for q, a in FAQ:
    BAGIAN_FAQ.append(f"<h3>{q}</h3>")
    BAGIAN_FAQ.append(f"<p>{a}</p>")

BACA_FAQ = ('<p><strong>BACA JUGA : <a href="https://www.tslaw.id/law-firm-surabaya/">law firm '
            'Surabaya</a> — panduan lengkap soal jenis layanan, kisaran biaya, dan cara menilai '
            'kredibilitas advokat.</strong></p>')

new = "\n".join(["\n".join(BAGIAN), "", WA_BTN.strip(), "", BACA.strip(), "",
                 "\n".join(BAGIAN_FAQ), BACA_FAQ]) + "\n"

plain = lambda s: htmlmod.unescape(re.sub(r"<[^>]+>", "", s)).strip()
schema = {"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [
    {"@type": "Question", "name": plain(q), "acceptedAnswer": {"@type": "Answer", "text": plain(a)}}
    for q, a in FAQ]}
new += '<script type="application/ld+json">' + json.dumps(schema, ensure_ascii=False) + "</script>\n"

# ---------------- aturan tetap: sapaan + nama kantor ----------------
new = re.sub(r"\bkamu\b", "Anda", new)
new = re.sub(r"\bKamu\b", "Anda", new)
new = new.replace("TSLaw", "TS Law")
new = re.sub(r"[ \t]{2,}", " ", new)

# ---------------- judul + meta selaras kueri nyata ----------------
TITLE = "Pengacara Surabaya Terbaik: 7 Hal yang Perlu Dinilai Sebelum Menunjuk"
SEO_TITLE = "Pengacara Surabaya Terbaik: 7 Cara Menilainya"
FOKUS = "pengacara surabaya terbaik"
META = ("Pengacara Surabaya terbaik untuk kasus bisnis dinilai dari izin praktik, rekam jejak, "
        "spesialisasi, dan kejelasan biaya. Ini 7 hal yang perlu dicek.")

assert 120 <= len(META) <= 158, f"meta {len(META)} char di luar 120-158"
assert META.lower().startswith(FOKUS), "meta tidak diawali fokus kw"
assert len(SEO_TITLE) <= 60, f"seo title {len(SEO_TITLE)} char"
assert FOKUS in (SEO_TITLE + " " + META + " " + TITLE).lower(), "fokus kw tidak ada di judul/meta"
for tok in ["7 hal", "izin praktik", "biaya"]:
    assert tok in (SEO_TITLE + " " + META).lower(), f"token '{tok}' tidak ada di judul/meta"
assert "TSLaw" not in new, "nama lama TSLaw masih ada"
assert new.count("https://www.tslaw.id/law-firm-surabaya/") == 1, f"tautan pilar bukan tepat 1 ({new.count('https://www.tslaw.id/law-firm-surabaya/')})"
assert new.count("wa.me/6281909222026") == 1, "tombol WA hilang/berubah"
assert new.count('"@type": "FAQPage"') == 1, "schema FAQPage tidak tepat 1"
assert len(re.findall(r"<h3>", new)) == len(FAQ) == len(schema["mainEntity"]), "FAQ tampil vs schema tidak sinkron"
assert not re.findall(r"\{[A-Za-z_\[\]0-9]+\}", new), "masih ada placeholder {..}"
assert not re.search(r"<p>[^<]*<p>", new), "masih ada <p> bersarang"
assert "</p></p>" not in new and "<p></p>" not in new, "paragraf bersarang/kosong"
assert "kamu" not in new.lower(), "sapaan 'kamu' masih ada"
assert "sudah ma." not in new and "memberikan ." not in new, "H2 terpotong masih ada"

for url in sorted(set(re.findall(r'href="(https://www\.tslaw\.id/[^"]+)"', new))):
    assert url.endswith("/") and url.count(" ") == 0, f"tautan janggal: {url!r}"
    print("   tautan internal:", url)

for tag in ["p", "h2", "h3", "ul", "li", "div", "script", "strong", "a"]:
    b = len(re.findall(rf"<{tag}[ >]", new)) - len(re.findall(rf"</{tag}>", new))
    assert b == 0, f"tag <{tag}> tidak seimbang ({b})"

KATA_SESUDAH = wc(new)
print(f"[sesudah] kata={KATA_SESUDAH} ({KATA_SESUDAH - KATA_SEBELUM:+d})")
print(f"[sesudah] H1={TITLE!r} ({len(TITLE)} char)")
print(f"[sesudah] seo={SEO_TITLE!r} ({len(SEO_TITLE)} char)")
print(f"[sesudah] meta={META!r} ({len(META)} char) | fokus={FOKUS!r}")
print(f"[sesudah] H2={len(re.findall(r'<h2', new))} H3={len(re.findall(r'<h3', new))} | "
      f"FAQ={len(FAQ)} | pilar=1 | WA=1 | schema=1")

open(f"{OUT}/post_{PID}_SESUDAH.html", "w").write(new)

if "--apply" not in sys.argv:
    print("\n[DRY RUN] tidak ada perubahan dikirim.")
    sys.exit(0)

kode, resp = rest_post(f"/posts/{PID}", {
    "title": TITLE, "content": new,
    "meta": {"_yoast_wpseo_focuskw": FOKUS, "_yoast_wpseo_title": SEO_TITLE,
             "_yoast_wpseo_metadesc": META}})
print(f"\nPOST /posts/{PID} -> HTTP {kode}")
if kode != 200:
    print(resp)
    sys.exit(1)
json.dump(resp if isinstance(resp, dict) else {"raw": resp},
          open(f"{OUT}/post_{PID}_POSTRESP.json", "w"), ensure_ascii=False, indent=1)
print("modified :", resp.get("modified"))
