#!/usr/bin/env python3
"""StudioSoft: artikel "Google Analytics 4 untuk Pemilik Bisnis".
Draf dulu (status=draft) + meta Yoast, gambar unggulan 1000x567 WebP.
Jalankan: python3 ss_artikel_ga4_pemilik_bisnis.py          (dry run)
          python3 ss_artikel_ga4_pemilik_bisnis.py --apply  (buat draf)
"""
import base64, json, re, sys, time, urllib.error, urllib.request
from io import BytesIO

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
DOM = "studiosoft.id"
AUTH = base64.b64encode(b"bambangbot:q26r RePo BVy6 pwU2 F3z7 ouyl").decode()

JUDUL = "Google Analytics 4 untuk Pemilik Bisnis: Laporan yang Perlu Dibuka Tiap Bulan"
SLUG = "google-analytics-4-untuk-pemilik-bisnis"
FOKUS = "google analytics 4 untuk pemilik bisnis"
META_JUDUL = "GA4 untuk Pemilik Bisnis: Laporan yang Perlu Dibuka"
META_DESC = ("Google Analytics 4 untuk pemilik bisnis tidak perlu rumit: buka laporan akuisisi, "
             "keterlibatan, dan peristiwa kunci, lalu baca angkanya dengan urutan benar.")
KATEGORI = [26]  # Digital Marketing

WA = ("https://wa.me/6281935000624?text=Halo%20StudioSoft%2C%20saya%20ingin%20konsultasi"
      "%20digital%20marketing")
TOMBOL = ('<p style="text-align:center;margin:32px 0 8px"><a href="' + WA +
          '" target="_blank" rel="noopener" style="display:inline-block;background-color:#0f2557;'
          'color:#ffffff;padding:15px 34px;font-size:18px;font-weight:bold;text-decoration:none;'
          'border-radius:6px;">Konsultasi Gratis</a></p>')

L_GSC = "https://studiosoft.id/google-search-console-untuk-pemula-7-manfaat-wajib-untuk-website-bisnis-naik-peringkat-google/"
L_LAPORAN = "https://studiosoft.id/laporan-seo-bulanan-angka-wajib/"
L_JASA = "https://studiosoft.id/jasa-seo-surabaya/"

BLOK = [
    '<p>Sebagian besar pemilik bisnis membuka Google Analytics 4 sekali, melihat beranda yang penuh grafik, lalu menutupnya lagi. Datanya berguna. Yang tidak ada adalah penjelasan soal angka mana yang perlu dilihat lebih dulu, dan apa artinya bagi penjualan.</p>',

    '<p>Urutan pembacaan di bawah ini bisa Anda pakai tiap bulan: dari mana pengunjung datang, apakah halamannya benar-benar dibaca, dan tindakan apa yang tercatat sebagai hasil. Semua laporan yang disebut ada di menu standar GA4, tanpa alat tambahan.</p>',

    '<h2>Kenapa GA4 terasa lebih rumit dari versi sebelumnya</h2>',

    '<p>Versi lama Analytics memberi satu laporan lalu lintas yang sudah dikelompokkan rapi. GA4 memecah informasi itu ke beberapa menu, dan sebagian istilahnya berubah. Sesi sekarang dibagi menjadi sesi dan sesi terlibat, sementara konversi berganti nama menjadi peristiwa kunci.</p>',

    '<p>Perubahan itu masuk akal karena GA4 mengukur kejadian, bukan sekadar kunjungan halaman. Konsekuensinya bagi Anda sederhana: tentukan pertanyaan yang ingin dijawab sebelum membuka menu mana pun. Tanpa pertanyaan, semua grafik terlihat sama pentingnya.</p>',

    '<h2>Mulai dari laporan akuisisi, bukan dari beranda</h2>',

    '<p>Buka Reports, lanjut ke Acquisition, lalu pilih Traffic acquisition. Di situ terlihat kanal yang mengirim pengunjung: pencarian organik, iklan berbayar, rujukan dari situs lain, media sosial, dan direct.</p>',

    '<p>Yang sering mengejutkan, kanal direct biasanya berisi lebih banyak orang daripada dugaan. Isinya bukan hanya pengunjung yang mengetik alamat situs. Tautan tanpa penanda pelacakan, halaman yang dibuka dari aplikasi lain, dan sebagian pesan WhatsApp juga masuk ke sana. Jadi sebelum menyimpulkan bahwa merek Anda sudah dikenal, periksa dulu apakah tautan kampanye memakai penanda yang benar.</p>',

    '<p>Kanal organik juga perlu dibaca dengan sadar bahwa GA4 dan Search Console mengukur hal berbeda. Search Console mencatat tampilan di hasil pencarian, termasuk yang tidak berujung kunjungan, sedangkan GA4 mencatat sesi yang benar-benar terbuka. Selisih di antara keduanya wajar, dan penjelasan istilah dasarnya ada di panduan <a href="' + L_GSC + '">Google Search Console untuk pemula</a>.</p>',

    '<h2>Keterlibatan: apakah halaman benar-benar dibaca</h2>',

    '<p>Di menu Engagement ada laporan Pages and screens. Selain jumlah tampilan, lihat waktu terlibat rata-rata dan jumlah sesi terlibat. Dua angka itu menunjukkan apakah pengunjung tinggal cukup lama untuk membaca, atau langsung menutup tab.</p>',

    '<p>Ukuran ini lebih jujur daripada jumlah kunjungan. Satu halaman yang dibaca empat menit oleh lima puluh orang biasanya lebih berharga daripada halaman yang ditinggalkan dalam lima detik oleh dua ratus orang. Saat membandingkan artikel, bandingkan waktu terlibatnya, bukan hanya jumlah tampilannya.</p>',

    '<p>Perhatikan juga bahwa waktu terlibat tidak dihitung untuk kunjungan yang berakhir sebelum halaman selesai dimuat. Kalau banyak pengunjung pergi di detik pertama, masalahnya mungkin ada di kecepatan situs, bukan di isi halaman.</p>',

    '<h2>Konversi: peristiwa yang harus Anda tandai sendiri</h2>',

    '<p>GA4 tidak tahu apa yang penting bagi bisnis Anda sampai Anda memberitahunya. Klik tombol WhatsApp, pengiriman formulir, dan panggilan telepon perlu ditandai sebagai peristiwa kunci agar muncul di laporan hasil.</p>',

    '<p>Mulai dari satu atau dua peristiwa yang benar-benar mewakili permintaan penawaran. Menandai terlalu banyak tombol membuat laporan konversi kehilangan arti, karena hampir setiap kunjungan akhirnya terhitung sebagai hasil. Setelah peristiwanya dipasang, uji lewat DebugView sebelum mempercayai angkanya. Satu klik yang tidak tercatat akan membuat seluruh laporan bulan itu menyesatkan.</p>',

    '<h2>Halaman pendaratan: mana yang mendatangkan kontak</h2>',

    '<p>Laporan halaman biasa menunjukkan halaman yang paling sering dilihat, tapi belum menjawab halaman mana yang menghasilkan kontak. Untuk itu buat satu eksplorasi sederhana yang memasangkan halaman pendaratan dengan peristiwa kunci, lalu urutkan dari jumlah peristiwa terbanyak.</p>',

    '<p>Bedanya penting. Halaman yang banyak dibaca bisa jadi artikel panduan yang memang tidak dimaksudkan untuk menjual. Sebaliknya, halaman layanan yang dibaca sedikit orang bisa menyumbang sebagian besar permintaan penawaran. Memindahkan anggaran hanya berdasarkan jumlah tampilan akan mengarahkan uang ke tempat yang salah.</p>',

    '<h2>Angka yang layak dibuka tiap bulan</h2>',

    '<p>Anda tidak perlu semua metrik. Untuk laporan bulanan, empat angka ini sudah cukup menggambarkan keadaan:</p>',

    '<ul>',

    '<li>Pengguna aktif dan sesi terlibat, dipisahkan per kanal.</li>',

    '<li>Waktu terlibat rata-rata pada lima halaman teratas.</li>',

    '<li>Jumlah peristiwa kunci per kanal, bukan hanya totalnya.</li>',

    '<li>Pangsa trafik ponsel, untuk memastikan situs nyaman dipakai di layar kecil.</li>',

    '</ul>',

    '<p>Kalau empat angka itu disimpan dalam satu tabel sederhana setiap bulan, Anda punya riwayat yang bisa dibaca tanpa bergantung pada ingatan siapa pun. Contoh susunan laporan yang lebih lengkap ada di artikel <a href="' + L_LAPORAN + '">laporan SEO bulanan</a>.</p>',

    '<h2>Kesalahan membaca data yang sering terjadi</h2>',

    '<ul>',

    '<li>Membandingkan bulan berjalan dengan bulan sebelumnya yang jumlah harinya berbeda, lalu menyimpulkan ada penurunan.</li>',

    '<li>Melaporkan jumlah pengguna tanpa menyebut apakah orang yang sama datang berkali-kali.</li>',

    '<li>Mengabaikan pengaruh persetujuan cookie. Pengunjung yang menolak pelacakan tidak tercatat, jadi angka yang turun belum tentu berarti minat pasar ikut turun.</li>',

    '<li>Menilai kampanye hanya dari klik terakhir, padahal sebagian pembeli membaca beberapa halaman lebih dulu sebelum menghubungi.</li>',

    '</ul>',

    '<p>Satu hal lagi yang sering terlewat: properti standar menyimpan data rinci selama dua bulan, dan pengaturannya bisa diperpanjang sampai empat belas bulan. Kalau Anda berencana membandingkan dengan periode yang lebih lama, ubah pengaturan itu sekarang, bukan saat datanya sudah dibutuhkan.</p>',

    '<h2>Pertanyaan yang sering diajukan</h2>',
]

TANYA = [
    ("Apakah angka GA4 dan Search Console harus sama?",
     "Tidak, karena keduanya mengukur hal berbeda. Search Console mencatat tampilan di hasil pencarian, "
     "termasuk yang tidak berujung kunjungan, sedangkan GA4 mencatat sesi yang benar-benar terbuka. "
     "Selisih beberapa persen itu normal. Yang perlu dicurigai adalah selisih besar dan tetap, karena "
     "biasanya menandakan pelacakan yang belum terpasang di semua halaman."),
    ("Berapa lama data sebuah halaman baru bisa dipercaya?",
     "Beri waktu sekitar dua sampai empat pekan sebelum mengambil kesimpulan dari halaman baru, karena "
     "pola kunjungan awalnya belum stabil. Yang bisa Anda periksa lebih cepat adalah apakah peristiwanya "
     "tercatat dengan benar, bukan hasil akhirnya."),
    ("Kalau angkanya turun, apa yang diperiksa lebih dulu?",
     "Periksa perubahan di sisi teknis sebelum menyalahkan pasar: peluncuran ulang situs, perubahan "
     "template, pembaruan plugin, atau banner persetujuan yang baru dipasang. Setelah itu baru bandingkan "
     "kueri dan halaman yang kehilangan trafik."),
    ("Apakah perlu alat pihak ketiga untuk membaca GA4?",
     "Untuk kebutuhan bulanan, laporan standar ditambah satu eksplorasi biasanya cukup. Alat tambahan "
     "baru berguna ketika data iklan dan penjualan harus digabung dalam satu tampilan, atau ketika laporan "
     "perlu dikirim otomatis ke banyak orang setiap bulan."),
]

for q, a in TANYA:
    BLOK.append(f"<h3>{q}</h3>")
    BLOK.append(f"<p>{a}</p>")

BLOK += [
    TOMBOL,
    '<p>Kalau Anda ingin laporan bulanan yang bisa dibaca tanpa membuka dashboard sendiri, kami menyusunnya dari data GA4, Search Console, dan catatan pekerjaan bulan itu. Isinya berhenti pada keputusan: apa yang dilanjutkan dan apa yang dihentikan.</p>',
    '<p>Untuk gambaran pekerjaan yang diukur dengan cara ini, lihat halaman <a href="' + L_JASA + '">jasa SEO Surabaya</a> beserta tahapan dan laporan yang menyertainya.</p>',
]

FAQ_LD = {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [{"@type": "Question", "name": q,
                    "acceptedAnswer": {"@type": "Answer", "text": a}} for q, a in TANYA],
}

ISI = "\n".join(BLOK) + '\n<script type="application/ld+json">' + json.dumps(FAQ_LD, ensure_ascii=False) + "</script>"

UA = {"User-Agent": "Mozilla/5.0"}


def rest(p, method="GET", data=None):
    h = {"Authorization": f"Basic {AUTH}", **UA}
    body = None
    if data is not None:
        body = json.dumps(data).encode()
        h["Content-Type"] = "application/json"
    for attempt in range(3):
        try:
            r = urllib.request.Request(f"https://{DOM}{p}", data=body, headers=h, method=method)
            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().decode()[:300]
        except Exception as e:
            time.sleep(4 + attempt * 3)
    return 0, "gagal koneksi"


teks = re.sub(r"<[^>]+>", " ", ISI).replace("&nbsp;", " ")
kata = len(teks.split())
print(f"=== {JUDUL}")
print(f"   panjang: {kata} kata (baku 1.000-1.300)")
print(f"   judul SEO: {len(META_JUDUL)} karakter (maks 60)")
print(f"   meta desc: {len(META_DESC)} karakter (140-158) · mulai dgn fokus: {META_DESC.lower().startswith(FOKUS)}")
print(f"   h2: {len(re.findall('<h2>', ISI))} · h3: {len(re.findall('<h3>', ISI))} · FAQPage: {'FAQPage' in ISI}")
n_dash = ISI.count(chr(8212))
n_kutip = len(re.findall("[" + chr(8220) + chr(8221) + chr(8216) + chr(8217) + "]", ISI))
n_cjk = len(re.findall(r"[\u3000-\u9fff\uac00-\ud7af]", ISI))
print(f"   em dash: {n_dash} · kutip melengkung: {n_kutip} · CJK: {n_cjk}")
print(f"   tombol WA: {'ada' if WA in ISI else 'TIDAK ADA'} · tautan internal: {len(re.findall('studiosoft.id/', ISI))}")
patah = [m for m in re.findall(r"<(p|li|h2|h3)>([^<]*)</\1>", ISI) if "\n" in m[1]]
print(f"   patahan baris: {len(patah)}")

if kata < 1000 or kata > 1300:
    print("   ❌ panjang di luar baku, hentikan")
    sys.exit(1)

if "--apply" not in sys.argv:
    print("\n(dry run, pakai --apply untuk membuat draf)")
    sys.exit(0)

# --- gambar unggulan 1000x567 ---
from PIL import Image, ImageDraw, ImageFont

W, H = 1000, 567
img = Image.new("RGB", (W, H), (15, 27, 52))
d = ImageDraw.Draw(img)
for y in range(H):
    f = y / H
    d.line([(0, y), (W, y)], fill=(int(15 + 20 * f), int(27 + 25 * f), int(52 + 70 * f)))
for cx, cy, r, a in ((880, 90, 190, 26), (120, 500, 150, 22), (760, 470, 90, 18)):
    lay = Image.new("RGBA", (W, H), (0, 0, 0, 0))
    ImageDraw.Draw(lay).ellipse([cx - r, cy - r, cx + r, cy + r], fill=(255, 255, 255, a))
    img = Image.alpha_composite(img.convert("RGBA"), lay).convert("RGB")
d = ImageDraw.Draw(img)

FB = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
FR = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
f_badge = ImageFont.truetype(FB, 22)
f_judul = ImageFont.truetype(FB, 52)
f_kaki = ImageFont.truetype(FR, 21)

d.rectangle([56, 62, 66, 150], fill=(56, 189, 248))
badge = "PANDUAN PENGUKURAN"
bw = d.textlength(badge, font=f_badge)
d.rounded_rectangle([86, 62, 86 + bw + 44, 108], radius=23, fill=(37, 99, 235))
d.text((86 + 22, 72), badge, font=f_badge, fill=(255, 255, 255))

baris = ["Google Analytics 4", "untuk Pemilik Bisnis"]
y = 180
for b in baris:
    assert d.textlength(b, font=f_judul) <= W - 160, b
    d.text((86, y), b, font=f_judul, fill=(255, 255, 255))
    print(f"   lebar baris '{b}': {d.textlength(b, font=f_judul):.0f}px (maks {W-160})")
    y += 68

d.text((86, 340), "Laporan yang perlu dibuka tiap bulan, tanpa istilah rumit",
       font=f_kaki, fill=(203, 213, 225))
d.line([(86, 470), (914, 470)], fill=(71, 85, 105), width=2)
d.text((86, 492), "studiosoft.id  ·  StudioSoft Digital Agency Surabaya", font=f_kaki, fill=(148, 163, 184))

buf = BytesIO()
img.save(buf, "WEBP", quality=90, method=6)
gbr = buf.getvalue()
open(f"{WS}/ss_ga4_pemilik_bisnis_cover.webp", "wb").write(gbr)
print(f"   gambar: {len(gbr)/1024:.1f} KB · {W}x{H}")

# --- pre-flight slug ---
st, ada = rest(f"/wp-json/wp/v2/posts?slug={SLUG}&status=any&_fields=id,slug,status")
if isinstance(ada, list) and ada:
    print(f"   ❌ slug sudah dipakai: {ada}")
    sys.exit(1)
print(f"   slug '{SLUG}' bebas (HTTP {st})")

# --- 1. buat draf ---
st, d1 = rest("/wp-json/wp/v2/posts", "POST", {
    "title": JUDUL, "slug": SLUG, "content": ISI, "status": "draft",
    "categories": KATEGORI, "comment_status": "closed",
    "meta": {"_yoast_wpseo_title": META_JUDUL, "_yoast_wpseo_metadesc": META_DESC,
             "_yoast_wpseo_focuskw": FOKUS},
})
if not isinstance(d1, dict) or "id" not in d1:
    print("   ❌ gagal buat draf:", st, str(d1)[:300])
    sys.exit(1)
pid = d1["id"]
print(f"\n   ✅ draf #{pid} → {d1.get('link')}")

# --- 2. unggah gambar unggulan ---
h = {"Authorization": f"Basic {AUTH}", "User-Agent": "Mozilla/5.0",
     "Content-Type": "image/webp",
     "Content-Disposition": 'attachment; filename="ga4-pemilik-bisnis.webp"'}
r = urllib.request.Request(f"https://{DOM}/wp-json/wp/v2/media", data=gbr, headers=h, method="POST")
with urllib.request.urlopen(r, timeout=180) as x:
    med = json.loads(x.read())
mid = med["id"]
st, d2 = rest(f"/wp-json/wp/v2/media/{mid}", "POST",
              {"alt_text": "Ilustrasi panduan Google Analytics 4 untuk pemilik bisnis"})
st, d3 = rest(f"/wp-json/wp/v2/posts/{pid}", "POST", {"featured_media": mid})
print(f"   gambar unggulan: media #{mid} → {med.get('source_url')}")

# --- 3. baca balik ---
st, back = rest(f"/wp-json/wp/v2/posts/{pid}?context=edit&_fields=id,slug,status,title,content,meta,featured_media,categories")
raw = back["content"]["raw"]
m = back.get("meta") or {}
print(f"   baca balik: status={back['status']} slug={back['slug']} media={back['featured_media']} "
      f"kata={len(re.sub('<[^>]+>', ' ', raw).split())}")
print(f"   meta: {json.dumps({k: v for k, v in m.items() if 'yoast' in k}, ensure_ascii=False)[:260]}")
print(f"   isi utuh: {raw.strip() == ISI.strip()} · FAQPage: {'FAQPage' in raw} · WA: {WA in raw}")
print(f"   POST_ID={pid} MEDIA_ID={mid}")
