#!/usr/bin/env python3
"""Perbaikan harian tslaw.id 2026-10-04 — post 3233 /cara-lapor-polisi-penipuan-online/.

Prioritas 1 (tayangan ada, klik NOL): selaraskan judul SEO + meta desc + fokus kw ke kueri
nyata GSC -> "melaporkan penipuan online", "penipuan online lapor kemana",
"cara melaporkan penipuan online ke polisi", "lapor penipuan".
Prioritas 2: 771 -> 1.000+ kata dengan isi yang benar-benar menjawab kueri (kanal resmi
lapor + langkah ke bank), bukan padding.
Prioritas 5: tambah 1 tautan kontekstual ke halaman pilar /law-firm-surabaya/.
Bonus akurasi: "TTA Law Firm" -> "TS Law"; dasar hukum disesuaikan (KUHP baru UU 1/2023
berlaku sejak 2 Januari 2026, Pasal 378 KUHP tak lagi jadi acuan utama).

Jalankan tanpa argumen = dry run. Dengan --apply = tulis via REST (JSON) + verifikasi.
"""
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 = 3233
OUT = f"{WS}/tslaw_pemulihan/perbaikan_20261004"
os.makedirs(OUT, exist_ok=True)


def rest_get(path, timeout=90):
    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(html):
    t = htmlmod.unescape(re.sub(r"<script.*?</script>", " ", html, flags=re.S))
    t = re.sub(r"<[^>]+>", " ", t)
    return len(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)
print(f"[sebelum] kata={KATA_SEBELUM}")
print(f"[sebelum] title={p['title']['raw']!r}")
print(f"[sebelum] seo={p['meta'].get('_yoast_wpseo_title')!r}")
print(f"[sebelum] meta={p['meta'].get('_yoast_wpseo_metadesc')!r}")

new = raw

# ---------- 1. Seksi baru: kanal resmi (menjawab "penipuan online lapor kemana") ----------
A_TIPS = '<!-- wp:heading -->\n<h2 class="wp-block-heading">Tips Agar Laporan Cepat Diproses</h2>'
assert raw.count(A_TIPS) == 1, "anchor Tips tidak unik"
KANAL = """<h2 class="wp-block-heading">Penipuan Online Lapor Kemana? Ini Kanal Resminya</h2>
<p>Pertanyaan pertama yang muncul setelah korban sadar tertipu biasanya bukan soal pasal, melainkan: penipuan online lapor kemana? Ada beberapa pintu yang sebaiknya Anda pakai sekaligus, bukan hanya salah satu.</p>
<ul>
<li><strong>SPKT Polres atau Polda setempat.</strong> Sentra Pelayanan Kepolisian Terpadu adalah pintu masuk paling umum. Datang langsung, bawa bukti, dan minta dibuatkan Laporan Polisi (LP).</li>
<li><strong>Unit Cyber Crime (Ditreskrimsus) Polda.</strong> Kalau nilai kerugian besar atau pelaku berada di provinsi lain, laporan bisa langsung diarahkan ke unit siber Polda agar penanganannya lebih terarah.</li>
<li><strong>Portal Patroli Siber Polri (patrolisiber.id).</strong> Kanal pengaduan resmi untuk kejahatan siber. Cocok sebagai laporan awal, tetapi laporan yang masuk tahap penyidikan tetap memerlukan LP yang dibuat di kantor polisi.</li>
<li><strong>Bank penerbit rekening.</strong> Hubungi call center bank untuk meminta pemblokiran rekening penampung dan penahanan dana. Ini langkah paling mendesak, karena uang bisa berpindah lagi dalam hitungan menit.</li>
<li><strong>OJK lewat Kontak OJK 157.</strong> Khusus penipuan berkedok investasi, robot trading, atau pinjaman online ilegal, OJK bisa menindak penyelenggara yang tidak berizin.</li>
<li><strong>Aduan Konten (aduankonten.id) dan cekrekening.id.</strong> Layanan Kementerian Komunikasi dan Digital untuk melaporkan konten penipuan, sekaligus memeriksa dan melaporkan nomor rekening yang dipakai pelaku agar diblokir.</li>
</ul>
<p>Tidak ada salahnya melapor ke lebih dari satu kanal. Justru kombinasi laporan polisi, permintaan blokir ke bank, dan aduan konten yang membuat pelaku kehilangan ruang gerak paling cepat.</p>
"""
new = new.replace(A_TIPS, KANAL + A_TIPS, 1)

# ---------- 2. Seksi baru: urutan lapor bank dulu + tautan pilar ----------
A_HUKUM = '<!-- wp:heading -->\n<h2 class="wp-block-heading">Dasar Hukum Penipuan Online</h2>'
assert raw.count(A_HUKUM) == 1, "anchor Dasar Hukum tidak unik"
BANK = """<h2 class="wp-block-heading">Lapor ke Bank Dulu, Baru ke Polisi</h2>
<p>Banyak korban baru menghubungi bank setelah beberapa hari berlalu. Padahal kecepatan adalah segalanya dalam penipuan transfer. Uang yang masuk ke rekening penampung biasanya dipindahkan lagi ke rekening lain dalam waktu singkat, sehingga peluang dana dibekukan menyusut setiap jam.</p>
<ul>
<li>Telepon call center bank, sebutkan bahwa Anda korban penipuan, lalu minta pemblokiran rekening penerima dan penahanan dana.</li>
<li>Catat nomor tiket pengaduan, tanggal, jam, serta nama petugas yang melayani Anda.</li>
<li>Minta berita acara atau surat keterangan pengaduan. Dokumen ini berguna saat Anda memperkarakan kasusnya.</li>
<li>Laporkan juga ke platform tempat transaksi terjadi, misalnya marketplace atau dompet digital, supaya akun pelaku ditangguhkan.</li>
</ul>
<p>Dalam praktik, bank sering baru bisa menahan dana setelah ada Laporan Polisi. Karena itu urutan yang paling efektif adalah: amankan bukti, hubungi bank, lalu buat LP pada hari yang sama. Jangan menunggu pelaku menjawab pesan Anda.</p>
<p>Kalau nilai kerugian besar atau pelakunya terorganisir, pendampingan dari <a href="https://www.tslaw.id/law-firm-surabaya/">law firm Surabaya</a> membantu menyusun kronologi yang rapi, menyiapkan somasi, sampai menggugat ganti rugi bila jalur pidana tidak mengembalikan dana Anda.</p>
"""
new = new.replace(A_HUKUM, BANK + A_HUKUM, 1)

# ---------- 3. Perbarui dasar hukum + perbaiki nama kantor ----------
old_hukum = ('<p>Penipuan online bisa dijerat dengan beberapa pasal: Pasal 378 KUHP tentang penipuan, '
             'Pasal 28 ayat (1) UU ITE tentang penyebaran berita bohong, dan Pasal 45A ayat (1) UU ITE. '
             'Untuk kasus penggelapan, bisa menggunakan Pasal 372 KUHP. Konsultasikan dengan '
             '<a href="https://www.tslaw.id">pengacara profesional dari TTA Law Firm</a> untuk menentukan pasal yang tepat.</p>')
assert raw.count(old_hukum) == 1, "paragraf dasar hukum tidak ditemukan"
new_hukum = ('<p>Penipuan online tidak dijerat dengan satu pasal saja, karena dasar hukumnya bergantung pada modusnya. '
             'Untuk penipuan umum, sejak 2 Januari 2026 KUHP lama digantikan KUHP baru (UU No. 1 Tahun 2023), '
             'sehingga acuan pidana penipuan kini berada di KUHP baru dan bukan lagi Pasal 378 KUHP.</p>\n'
             '<!-- /wp:paragraph -->\n\n'
             '<!-- wp:paragraph -->\n'
             '<p>Penipuan yang dilakukan lewat media elektronik tetap bisa dikenakan Pasal 28 ayat (1) juncto '
             'Pasal 45A ayat (1) UU ITE sebagaimana diubah oleh UU No. 1 Tahun 2024. Jika uang digelapkan oleh '
             'pihak yang dipercaya, polisi biasanya menjeratnya dengan pasal penggelapan, bukan penipuan.</p>\n'
             '<!-- /wp:paragraph -->\n\n'
             '<!-- wp:paragraph -->\n'
             '<p>Karena pemilihan pasal menentukan arah penyidikan, ada baiknya Anda berdiskusi lebih dulu dengan '
             '<a href="https://www.tslaw.id">advokat dari TS Law</a> agar laporan yang Anda buat sejak awal '
             'sudah mengarah ke pasal yang tepat.</p>')
new = new.replace(old_hukum, new_hukum, 1)

# ---------- 4. Kesimpulan: perbaiki nama kantor ----------
old_kes = ('Jika membutuhkan pendampingan hukum, <a href="https://www.tslaw.id">hubungi TTA Law Firm</a> '
           'untuk konsultasi dan pendampingan profesional.')
assert raw.count(old_kes) == 1, "kalimat penutup tidak ditemukan"
new_kes = ('Jika membutuhkan pendampingan hukum, <a href="https://www.tslaw.id">hubungi TS Law</a> '
           'untuk konsultasi dan pendampingan profesional.')
new = new.replace(old_kes, new_kes, 1)

# ---------- 5. FAQ: tambah 2 tanya-jawab yang benar-benar tampil + schema ikut diperbarui ----------
m = re.search(r'<div class="wp-block-rank-math-faq-block">.*?\n</div>\n', raw, re.S)
assert m, "blok FAQ tidak ditemukan"
faq_old = m.group(0)
items = re.findall(
    r'<h3 class="rank-math-faq-question">(.*?)</h3><div class="rank-math-faq-answer"><p>(.*?)</p></div>',
    faq_old, re.S)
assert len(items) == 5, f"jumlah FAQ awal {len(items)} != 5"
faq = [[q, a] for q, a in items]
faq.append(["Penipuan online lapor kemana?",
            "Kanal utamanya SPKT Polres atau Polda setempat, dan untuk kasus siber bisa langsung ke Unit Cyber Crime "
            "(Ditreskrimsus) Polda. Laporkan juga ke bank penerbit rekening untuk meminta pemblokiran dana, ke OJK "
            "lewat Kontak OJK 157 bila terkait investasi atau pinjol ilegal, serta ke aduankonten.id untuk konten penipuannya."])
faq.append(["Apakah bisa lapor penipuan online tanpa datang ke kantor polisi?",
            "Bisa untuk tahap pengaduan awal lewat portal resmi Patroli Siber Polri di patrolisiber.id. Namun laporan "
            "yang masuk proses penyidikan tetap memerlukan Laporan Polisi yang dibuat dan ditandatangani di kantor polisi."])

faq_html = '<div class="wp-block-rank-math-faq-block">\n' + '\n'.join(
    '<div class="rank-math-faq-item"><h3 class="rank-math-faq-question">%s</h3>'
    '<div class="rank-math-faq-answer"><p>%s</p></div></div>' % (q, a) for q, a in faq) + '\n</div>\n'
new = new.replace(faq_old, faq_html, 1)

# komentar rank-math (JSON di dalam blok) ikut diselaraskan
def plain(s):
    return htmlmod.unescape(re.sub(r"<[^>]+>", "", s)).strip()

comment_json = json.dumps({"questions": [{"title": plain(q), "content": plain(a)} for q, a in faq]},
                          ensure_ascii=False, separators=(",", ":"))
m_c = re.search(r'<!-- wp:rank-math/faq-block \{.*?\} -->', new, re.S)
assert m_c, "komentar rank-math FAQ tidak ditemukan"
new = new[:m_c.start()] + '<!-- wp:rank-math/faq-block ' + comment_json + ' -->' + new[m_c.end():]

# schema FAQPage dibangun ulang dari FAQ yang tampil
schema = {"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [
    {"@type": "Question", "name": plain(q), "acceptedAnswer": {"@type": "Answer", "text": plain(a)}}
    for q, a in faq]}
schema_html = '<script type="application/ld+json">' + json.dumps(schema, ensure_ascii=False) + '</script>'
m_s = re.search(r'<script type="application/ld\+json">.*?</script>', new, re.S)
assert m_s, "script ld+json tidak ditemukan"
new = new[:m_s.start()] + schema_html + new[m_s.end():]

# ---------- 6. Judul + meta selaras kueri nyata ----------
TITLE = "Penipuan Online Lapor Kemana? Cara Melaporkan ke Polisi dan Bank"
SEO_TITLE = "Penipuan Online Lapor Kemana? Cara Melaporkan ke Polisi 2026"
FOKUS = "penipuan online lapor kemana"
META = ("Penipuan online lapor kemana? Ini kanal resminya: SPKT, Patroli Siber, OJK, sampai bank. "
        "Plus cara melaporkan penipuan online ke polisi dan bukti wajib.")

# ---------- validasi ----------
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).lower(), "fokus kw tidak ada di judul/meta"
for kw in ["penipuan online lapor kemana", "melaporkan penipuan online", "cara melaporkan"]:
    assert kw in (SEO_TITLE + " " + META).lower(), f"kueri '{kw}' tidak ada di judul/meta"
for tok in ["penipuan online", "lapor", "polisi"]:
    assert tok in (SEO_TITLE + " " + META).lower(), f"token '{tok}' tidak ada"
assert "TTA Law Firm" not in new, "TTA Law Firm masih ada"
assert new.count("law-firm-surabaya") == 1, "tautan pilar bukan tepat 1"
assert new.count("wa.me/6281909222026") == 1, "tombol WA hilang/berubah"
assert new.count('"@type": "FAQPage"') == 1, "schema FAQPage hilang"
assert not re.findall(r"\{[A-Za-z_\[\\\]0-9]+\}", new), "masih ada placeholder {..}"

KATA_SESUDAH = wc(new)
print(f"[sesudah] kata={KATA_SESUDAH} (+{KATA_SESUDAH - KATA_SEBELUM})")
print(f"[sesudah] title={TITLE!r}")
print(f"[sesudah] seo={SEO_TITLE!r} ({len(SEO_TITLE)} char)")
print(f"[sesudah] meta={META!r} ({len(META)} char)")
print(f"[sesudah] fokus={FOKUS!r} | FAQ={len(faq)} item | schema mainEntity={len(schema['mainEntity'])}")

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