#!/usr/bin/env python3
"""
Twitter @UkyHandoko — Scheduler 7 Slot (WIB) — GAYA BARU: HUMANIS & NGOMONGIN (FIXED 14 Agustus 2026)
Slot: 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00 (jeda 3 jam)
Nested: Post 1 → Reply 2 → Reply 3 (jeda 1 menit antar tweet)
Cek slot kosong via API Repliz (jadwal hari ini untuk akun Twitter).

Niche konten: quotes, motivasi, marketing strategi, digital marketing, SEO, GEO, AI Overview.
Gaya: bahasa Indonesia humanis, ngajak ngobrol, attractive, relatable — pakai "saya" & "kamu".

Aturan:
- Bahasa Indonesia humanis, ngajak ngobrol, pakai "saya" (bukan "gue")
- Konten unik — anti duplikasi via hash tracker
- Maks 280 karakter per tweet (Twitter) — teks utuh, JANGAN dipotong
- Link artikel WAJIB dicek 200 OK sebelum kirim (aturan link fix)
- Awareness StudioSoft: jangan terlihat jualan, bikin penasaran → link di akhir
- Cron tiap jam → isi slot kosong berikutnya
"""
import json, urllib.request, urllib.error, os, random, sys, hashlib, re
from datetime import datetime, timezone, timedelta

sys.path.insert(0, "/home/mantapman/.hermes/profiles/atun/workspace")
from repliz_client import AUTH, HEADERS, BASE, ACC

ACCOUNT_ID = ACC.UKY_TWITTER  # 6a792f0a62caae1e04f57992
LOG_FILE = "/home/mantapman/.hermes/profiles/atun/workspace/twitter_uky_log.txt"
THEME_TRACK_FILE = "/home/mantapman/.hermes/profiles/atun/workspace/.twitter_theme_hashes.json"

WIB = timezone(timedelta(hours=7))
MAX_CHARS = 280  # batas Twitter

# ==================== 7 SLOT WAKTU WIB ====================
SLOT_WIB = ["05:00", "08:00", "11:00", "14:00", "17:00", "20:00", "23:00"]
SLOT_HOURS = [5, 8, 11, 14, 17, 20, 23]

# ==================== GREETINGS — NGOMONGIN, BUKAN FORMAL ====================
GREETINGS = [
    "Ngobrol santai dulu yuk!",
    "Eh, mampir dulu — ada satu hal yang pengen saya bahas.",
    "Sambil ngopi, ngobrol seru yuk!",
    "Halo, lama nggak ngobrol!",
    "Hari ini pengen bahas yang ringan-ringan dulu.",
    "Btw, ada yang menarik buat dibahas nih.",
]

# ==================== BANK CTA (bikin respon — gaya ngobrol) ====================
CTA_BANK = [
    "Setuju? Curhat di kolom komentar yuk!",
    "Menurut kamu gimana? Cerita dong di komentar \U0001F447",
    "Pernah ngalamin juga? Share di kolom komentar!",
    "Debat sehat boleh banget — tulis di komentar!",
    "Kamu tim yang mana? Komentar yuk!",
    "Penasaran lanjutannya? Tanya di komentar aja!",
    "Ada pengalaman serupa? Cerita di kolom komentar!",
    "Dari sudut pandangmu, gimana? Komentar ya!",
]

# ==================== BANK KONTEN — GAYA ASIK, NGOMONGIN ====================
# Struktur: post → reply1 → reply2 (nested 3 level)
# Niche: quotes, motivasi, marketing strategi, digital marketing, SEO, GEO, AI Overview
THEMES = [
    # ── QUOTES (orisinal, relatable, gak lebay) ──
    {
        "theme": "quote konsisten",
        "post": "{greet} Konsisten itu bukan soal semangat — soal sistem. Orang yang semangatnya naik-turun kalah sama orang yang cuma butuh 30 menit sehari, tapi nggak pernah bolong. Kecil, pelan, tapi jalan terus.",
        "reply1": "Semangat itu bohong kalau cuma sekali dua kali. Yang bikin beda itu: datang lagi besok, besoknya lagi, dan seterusnya. Persis kayak bangun otot.",
        "reply2": "Mulai dari 30 menit sehari buat hal yang kamu anggap penting. Sebulan lagi kamu bakal kaget sendiri sama hasilnya.",
    },
    {
        "theme": "quote waktu",
        "post": "{greet} Waktu nggak nunggu kita siap. Kamu nunggu 'mood bagus' buat mulai, orang lain udah mulai duluan dengan keadaan pas-pasan. Siap itu ilusi — mulai itu pilihan.",
        "reply1": "Semua orang punya 24 jam yang sama. Bedanya cuma satu: ada yang pakai buat nunda, ada yang pakai buat jalan. Mau pilih yang mana?",
        "reply2": "Kalau nunggu siap, nggak akan pernah mulai. Jadi mulai aja — sisanya belajar sambil jalan.",
    },
    {
        "theme": "quote gagal",
        "post": "{greet} Gagal itu bukan lawan — dia guru yang paling jujur. Yang bikin orang berhenti bukan kegagalannya, tapi cerita yang dia ulang-ulang di kepalanya sendiri.",
        "reply1": "Coba ganti kalimatnya: dari 'kenapa saya gagal lagi' jadi 'pelajaran apa yang bisa saya ambil'. Ajaib, semuanya langsung kerasa beda.",
        "reply2": "Orang sukses itu bukan yang nggak pernah jatuh. Mereka cuma kebiasaan bangun lebih cepat dari rasa malunya.",
    },
    {
        "theme": "quote kecil",
        "post": "{greet} Jangan remehin langkah kecil. Setiap hari nambah 1% itu setahun jadi 37 kali lipat. Masalahnya, kebanyakan orang berhenti di minggu pertama karena belum lihat hasil.",
        "reply1": "Hasil itu telat, proses itu cepat. Kalau kamu fokus ke prosesnya — nambah dikit tiap hari — hasilnya bakal nyusul sendiri.",
        "reply2": "Hari ini tambah 1% aja dulu. Nggak usah muluk-muluk. Buktikan seminggu, terus lihat bedanya.",
    },
    {
        "theme": "quote fokus",
        "post": "{greet} Fokus itu bukan soal banyak hal yang dikerjain, tapi soal banyak hal yang kamu tolak. Setiap 'iya' ke satu hal, artinya 'tidak' ke seratus hal lain. Pilih yang penting.",
        "reply1": "Kita nggak kekurangan ide — kita kekurangan fokus. Satu ide yang digarap tuntas, menang telak dari sepuluh ide yang setengah-setengah.",
        "reply2": "Tulis 3 prioritas kamu hari ini. Sisanya, istirahat dulu. Besok kamu bakal lihat bedanya.",
    },

    # ── MOTIVASI (dorongan nyata, bukan template) ──
    {
        "theme": "motivasi mulai",
        "post": "{greet} Nggak ada kata 'terlambat' buat mulai belajar hal baru. Umur 40 baru belajar digital marketing? Banyak yang sukses justru dari situ. Yang rugi itu yang nggak mulai sama sekali.",
        "reply1": "Kita sering nunda karena mikir 'ah udah telat'. Padahal 5 tahun lagi, kamu bakal berharap mulai dari sekarang. Mulai hari ini — besok kamu udah 1 hari lebih maju.",
        "reply2": "Satu kelas, satu tutorial, satu artikel sehari. Itu udah cukup buat mulai. Yang penting gerak dulu.",
    },
    {
        "theme": "motivasi proses",
        "post": "{greet} Jangan bandingin bab 1 kamu sama bab 20 orang lain. Tiap orang punya garis start dan kecepatan yang beda. Yang kamu lihat cuma highlight mereka — bukan perjuangannya.",
        "reply1": "Fokus sama progress diri sendiri. Minggu lalu kamu masih bingung, sekarang udah bisa. Itu kemenangan kecil yang layak dirayain.",
        "reply2": "Catat progress kamu tiap minggu. Pas lagi down, baca lagi — biar inget seberapa jauh kamu udah jalan.",
    },
    {
        "theme": "motivasi diri",
        "post": "{greet} Kompetisi terberat itu bukan sama orang lain — sama diri sendiri kemarin. Kalau hari ini kamu lebih baik dikit dari kemarin, kamu udah menang. Sederhana, tapi jarang disadari.",
        "reply1": "Bandingin diri sama orang lain itu sumber stres yang nggak ada habisnya. Bandingin sama diri sendiri itu sumber motivasi yang nggak pernah kering.",
        "reply2": "Target hari ini: lebih baik 1% dari kemarin. Besok ulang lagi. Pelan, tapi nggak pernah mundur.",
    },
    {
        "theme": "motivasi action",
        "post": "{greet} Teori nggak akan pernah ngasih rasa percaya diri — action yang ngasih. Semakin sering kamu coba, semakin berani. Semakin banyak gagal, semakin tajam instingmu.",
        "reply1": "Orang yang 'udah baca banyak buku' belum tentu maju. Yang baca lalu langsung praktik, itu yang beda kelas.",
        "reply2": "Selesai baca ini, ambil satu hal kecil buat kamu kerjain sekarang. Jangan cuma disimpan sebagai rencana.",
    },
    {
        "theme": "motivasi sabar",
        "post": "{greet} Sabar itu bukan pasrah — sabar itu kerja keras yang hasilnya belum keliatan. Kayak nanam pohon: kamu siram tiap hari, tapi buahnya baru muncul musim depan. Percaya sama prosesnya.",
        "reply1": "Yang sering terjadi: orang menyerah pas mau panen, karena lelahnya udah keburu terasa. Padahal tinggal selangkah lagi.",
        "reply2": "Kalau kamu udah jalan 6 bulan dan belum lihat hasil — mungkin justru itu tandanya lagi deket. Jangan berhenti sekarang.",
    },

    # ── MARKETING STRATEGI ──
    {
        "theme": "strategi kenali audiens",
        "post": "{greet} Marketing yang bagus dimulai dari satu pertanyaan: 'siapakah mereka yang paling butuh ini?' Bukan 'gimana biar semua orang beli'. Semua orang itu nggak ada — yang ada itu segmen-segmen.",
        "reply1": "Coba tulis profil pelanggan idealmu: umurnya, kerjaannya, masalahnya, dan di mana dia nongkrong. Dari situ semua strategi jadi lebih gampang disusun.",
        "reply2": "Banyak bisnis gagal bukan karena produk jelek, tapi karena ngomong ke semua orang — akhirnya nggak nyambung ke siapa-siapa.",
    },
    {
        "theme": "strategi brand janji",
        "post": "{greet} Brand itu bukan logo — brand itu janji. Setiap kali pelanggan beli, dia lagi ngetes apakah kamu tepati janji itu. Tepati terus, dan dia bakal balik lagi bawa temennya.",
        "reply1": "Janji yang gampang: 'murah'. Janji yang kuat: 'masalahmu beres'. Yang kedua yang bikin orang loyal.",
        "reply2": "Cek bisnismu: janji apa yang kamu kasih? Apakah semua orang di timmu tahu janji itu dan menjaganya?",
    },
    {
        "theme": "strategi positioning",
        "post": "{greet} Positioning itu bukan soal kamu jual apa, tapi soal kamu jadi apa di kepala pelanggan. Kalau ditanya 'jasa kamu ngapain?' dan jawabannya bertele-tele — positioningmu belum jelas.",
        "reply1": "Coba isi titik-titik ini: 'Untuk [siapa], saya adalah [apa], yang bisa [hasil apa].' Kalau bisa diisi dalam satu napas, berarti positioningmu udah tajam.",
        "reply2": "Satu kalimat positioning yang jelas itu lebih mahal dari seribu kalimat iklan yang ambigu.",
    },
    {
        "theme": "strategi storytelling",
        "post": "{greet} Orang nggak inget angka — orang inget cerita. Produk yang sama bisa laku beda jauh cuma karena cara ceritanya beda. Mulai cerita dari masalah, bukan dari fitur.",
        "reply1": "Struktur cerita marketing yang manjur: kenalkan masalahnya, rasakan sakitnya, baru tawarkan jalan keluarnya. Pelanggan bakal ngerasa 'ini cerita saya'.  ",
        "reply2": "Fitur itu 'kamera 108MP'. Cerita itu 'hasil fotonya bikin dia nangis haru pas ulang tahun ibu'. Yang kedua yang di-share orang.",
    },
    {
        "theme": "strategi retensi",
        "post": "{greet} Paling mahal itu cari pelanggan baru. Paling murah itu jaga pelanggan lama. Tapi kebanyakan bisnis sibuk ngejar yang baru, lupa yang lama udah nunggu dibales chatnya.",
        "reply1": "Satu pelanggan puas itu bisa bawa 3-5 orang baru lewat cerita. Satu pelanggan kecewa bisa ngerusak reputasi di 10 grup WA. Jaga yang lama, yang baru ngikut sendiri.",
        "reply2": "Hari ini, bales duluan satu pelanggan lama yang belum kamu sapa. Lihat apa yang terjadi.",
    },

    # ── DIGITAL MARKETING ──
    {
        "theme": "dm konten raja",
        "post": "{greet} Konten itu raja, tapi konteks itu kerajaan. Konten bagus tanpa tahu siapa yang baca dan di mana dia baca — cuma jadi hiasan feed. Kenali konteksnya, baru bikin kontennya.",
        "reply1": "Konten yang sama bisa beda banget hasilnya di IG, TikTok, atau LinkedIn. Karena yang baca beda orang, beda suasana hati, beda harapan.",
        "reply2": "Sebelum bikin konten, jawab: siapa yang baca, lagi di mana, dan pengen dapet apa. Dari situ baru nulis.",
    },
    {
        "theme": "dm omni channel",
        "post": "{greet} Omnichannel itu bukan 'ada di semua platform'. Itu 'pelanggan bisa mulai di satu tempat dan selesai di tempat lain tanpa bingung'. Buka IG, liat produk, klik link, bayar, semua mulus.",
        "reply1": "Kebanyakan bisnis cuma numpang eksis di banyak tempat, tapi tiap tempat ceritanya beda-beda. Itu bikin bingung, bukan bikin percaya.",
        "reply2": "Cek perjalanan pelangganmu: dari liat iklan sampai bayar. Ada nggak titik yang bikin mereka mikir dua kali?",
    },
    {
        "theme": "dm data driven",
        "post": "{greet} 'Kira-kira' itu musuh marketing. Data itu bukan buat pamer laporan — data buat jawab: konten mana yang kerja, iklan mana yang boros, dan pelanggan dari mana yang paling sering beli.",
        "reply1": "Mulai dari 3 angka doang: berapa orang lihat, berapa yang klik, berapa yang beli. Dari situ kamu udah bisa bikin keputusan lebih pintar dari 90% kompetitor.",
        "reply2": "Kalau kamu belum ukur apa-apa, kamu cuma nebak. Dan nebak itu mahal.",
    },
    {
        "theme": "dm customer journey",
        "post": "{greet} Orang nggak langsung beli — mereka lewat perjalanan: sadar, tertarik, mikir, bandingin, baru beli. Marketing yang baik ngasih konten yang pas di tiap tahap itu, bukan cuma teriak 'beli! beli!'",
        "reply1": "Tahap sadar: kasih edukasi. Tahap mikir: kasih bukti & testimoni. Tahap mau beli: kasih tawaran yang gampang. Satu tahap salah, pelanggan kabur.",
        "reply2": "Coba petakan: kontenmu sekarang lagi ngomong ke orang di tahap mana? Kalau semua ke tahap beli, wajar kalau yang masih mikir nggak ngerespon.",
    },
    {
        "theme": "dm email marketing",
        "post": "{greet} Email marketing itu kayak rumah sendiri di tengah pasar yang rame. Sosmed bisa ganti algoritma kapan aja, tapi email yang udah kamu kumpulin tetep milikmu. Jangan sepelein daftar email.",
        "reply1": "Mulai sekarang: tiap kali ada yang beli atau tanya, tawarin newsletter. Satu email tiap minggu yang isinya bermanfaat — bukan cuma jualan.",
        "reply2": "Pelanggan yang buka email itu pelanggan yang udah percaya. Dan yang udah percaya itu yang paling gampang diajak beli lagi.",
    },

    # ── SEO ──
    {
        "theme": "seo bukan instan",
        "post": "{greet} SEO itu kayak nanam pohon: 3 bulan pertama kelihatannya nggak ada apa-apa, padahal akarnya lagi jalan di bawah tanah. Yang sabar, 6 bulan kemudian panen traffic tanpa bayar iklan.",
        "reply1": "Iklan itu instan tapi berhenti pas budget habis. SEO itu lambat tapi efeknya numpuk — makin lama makin kuat, dan nggak hilang cuma karena bulan depan.",
        "reply2": "Kalau bisnismu butuh hasil bulan ini, pakai iklan. Tapi sambil jalan, tetep nanam pohon SEO. 6 bulan lagi kamu bakal berterima kasih.",
    },
    {
        "theme": "seo user intent",
        "post": "{greet} Google makin pinter baca niat. Orang ngetik 'sepatu murah' itu beda banget sama 'sepatu lari buat pemula'. Konten yang jawab niatnya, bukan cuma nempel kata kuncinya, yang bakal menang.",
        "reply1": "Cara gampangnya: sebelum nulis, tanya 'orang yang ngetik ini lagi pengen ngapain?' Terus jawab pertanyaan itu sampai tuntas.",
        "reply2": "Konten yang jawab niat pencarian itu yang bikin Google nganggep kamu relevan. Relevan itu setengah dari pekerjaan SEO.",
    },
    {
        "theme": "seo e-e-a-t",
        "post": "{greet} SEO sekarang nggak cuma soal kata kunci — soal pengalaman, keahlian, otoritas, dan kepercayaan. Google pengen nyajiin jawaban dari orang yang beneran ngerti, bukan dari konten hasil copy-paste.",
        "reply1": "Cara nunjukin keahlian: tulis pengalaman nyata, kasih nama & identitas jelas, kutip sumber, dan update konten lama yang udah basi. Detail kecil, efek gede.",
        "reply2": "Mulai hari ini: tambahin halaman 'tentang' yang jujur & manusiawi di websitemu. Itu salah satu sinyal kepercayaan paling gampang.",
    },
    {
        "theme": "seo lokal",
        "post": "{greet} Bisnis lokal, dengerin: orang cari 'kafe dekat saya', 'klinik terdekat', 'bengkel murah'. Mereka nggak cari 'terbaik se-Indonesia'. Kalau kamu nggak muncul di Google Maps, kamu dilewatin diam-diam.",
        "reply1": "Yang wajib: Google Business Profile diisi lengkap, foto bagus, jam buka bener, dan review dibales rutin. Itu udah 70% perang SEO lokal.",
        "reply2": "Coba sekarang: search nama bisnismu di Google Maps. Lihat? Itu yang dilihat calon pelangganmu sebelum mutusin dateng atau nggak.",
    },
    {
        "theme": "seo konten menjawab",
        "post": "{greet} Rahasia SEO yang jarang dibahas: konten yang menang itu yang bikin orang berhenti scroll. Bukan yang paling panjang, bukan yang paling banyak kata kunci — tapi yang paling langsung jawab.",
        "reply1": "Coba format begini: judul = pertanyaan, paragraf pertama = jawaban langsung, sisanya = detail. Singkat, padat, dan Google suka.",
        "reply2": "Tulis konten kayak lagi jelasin ke temen sendiri. Nggak kaku, nggak bertele-tele. Itu yang dibaca orang sampai habis.",
    },

    # ── GEO ──
    {
        "theme": "geo apa itu",
        "post": "{greet} Pernah denger GEO? Generative Engine Optimization — optimasi biar bisnismu jadi jawaban di AI search kayak ChatGPT, Perplexity, atau Gemini. Bedanya sama SEO: AI nyari sumber yang jelas, terstruktur, dan dipercaya.",
        "reply1": "GEO itu kayak SEO versi 2.0. Kalau SEO bikin kamu muncul di daftar biru Google, GEO bikin kamu dikutip sebagai jawaban AI — lengkap dengan sumbernya.",
        "reply2": "Mulai kenalan sekarang, karena kebiasaan orang cari jawaban udah mulai pindah dari daftar link ke kotak jawaban AI.",
    },
    {
        "theme": "geo vs seo",
        "post": "{greet} SEO vs GEO, bedanya apa? SEO nyariin traffic dari halaman hasil pencarian. GEO nyariin 'dikutip' sama AI saat orang nanya. Dua-duanya penting — yang pertama masih jalan, yang kedua lagi naik.",
        "reply1": "Analogi simpelnya: SEO itu biar tokomu keliatan di jalan raya. GEO itu biar tokomu yang direkomendasiin orang pintar ke temennya.",
        "reply2": "Jangan milih salah satu — jalanin dua-duanya. Konten bagus yang terstruktur itu sebenernya udah nutupin dua-duanya sekaligus.",
    },
    {
        "theme": "geo optimasi",
        "post": "{greet} Cara optimasi GEO yang gampang dimulai: bikin FAQ yang jawabannya langsung, pakai heading yang rapi, kasih data & sumber jelas, dan tulis kayak manusia — bukan kayak robot isi template.",
        "reply1": "AI search itu doyan konten yang 'bisa dicomot'. Artinya: jawaban ada di paragraf pertama, nggak dikubur di kalimat ke-sepuluh.",
        "reply2": "Coba tes: tanya ChatGPT soal bisnismu. Kalau dia jawab asal-asalan atau salah — itu PR GEO kamu.",
    },
    {
        "theme": "geo masa depan",
        "post": "{greet} Masa depan pencarian itu percakapan, bukan daftar link. Orang makin sering nanya ke AI: 'rekomendasiin klinik gigi yang bagus di Surabaya'. Kalau bisnismu nggak ada di data yang AI baca — kamu nggak akan direkomendasiin.",
        "reply1": "Yang AI baca itu dari mana? Dari konten publik yang jelas, konsisten, dan sering dirujuk. Makanya website & konten yang rapi itu makin berharga.",
        "reply2": "Mulai sekarang: pastikan info bisnismu sama di semua tempat — website, Maps, sosmed. AI suka sumber yang konsisten.",
    },

    # ── AI OVERVIEW & AI ──
    {
        "theme": "ai overview",
        "post": "{greet} Pernah liat jawaban AI di paling atas hasil Google? Itu AI Overview. Dan mulai sekarang, konten kamu harus layak 'dicomot' AI buat jadi jawaban — kalau nggak, trafficnya dicomot orang lain.",
        "reply1": "Yang dicomot AI itu konten yang langsung jawab, terstruktur rapi, dan dari sumber yang dianggap kredibel. Bukan yang muter-muter 3 paragraf baru nyampe inti.",
        "reply2": "Cek topik utama bisnismu di Google sekarang. Kalau jawaban AI-nya dari kompetitor — kamu tau harus ngapain.",
    },
    {
        "theme": "ai tools harian",
        "post": "{greet} AI udah jadi asisten harian saya: riset topik, bikin outline, nyusun data, sampai ngecek grammar. Bukan buat ngerjain semuanya — buat ngerjain yang berat-berat, biar saya fokus ke strategi.",
        "reply1": "Kuncinya satu: makin jelas perintahmu ke AI, makin bagus hasilnya. 'Bikin konten' itu perintah malas. 'Bikin 5 ide judul buat klinik gigi, nada santai' itu perintah kerja.",
        "reply2": "Kalau kamu masih nol, mulai dari yang gampang: minta AI ngerangkum artikel panjang jadi 3 poin. Besok baru naik level.",
    },
    {
        "theme": "ai plus manusia",
        "post": "{greet} AI + manusia itu tim terkuat: AI buat kecepatan, manusia buat rasa. AI bisa nulis 1000 kata dalam 10 detik, tapi cuma manusia yang tau mana yang bikin pembaca ngerasa 'wah, ini ngomongin saya'.",
        "reply1": "Cara pakai yang sehat: AI buat draft pertama, kamu rombak dengan pengalaman & gaya sendiri, baru publish. Hasilnya konten cepat yang nggak kehilangan jiwa.",
        "reply2": "Jangan takut AI — takutlah sama orang yang udah jago pakai AI sementara kamu masih mikirin mau mulai dari mana.",
    },
    {
        "theme": "ai content pribadi",
        "post": "{greet} Konten terbaik di era AI justru yang paling manusiawi. Karena makin banyak konten generik dari AI, makin berharga cerita, pengalaman, dan opini yang cuma bisa kamu kasih.",
        "reply1": "AI bisa tiru gayamu, tapi nggak bisa niru pengalamanmu: kegagalanmu, pelajaranmu, momen 'aha' kamu. Itu aset yang nggak bisa di-generate.",
        "reply2": "Tulis satu pengalaman nyata kamu minggu ini terus post. Itu konten yang nggak akan pernah bisa disaingin AI.",
    },

    # ── AWARENESS ARTIKEL STUDIOSOFT / DMARK (link di akhir — bikin penasaran, bukan jualan) ──
    {
        "theme": "artikel seo umkm",
        "post": "{greet} Banyak UMKM mikir: 'SEO mah buat perusahaan gede.' Padahal justru UMKM yang paling diuntungkan — saingan di Google belum tentu banyak, dan halaman pertama itu masih mungkin diraih tanpa budget gede.",
        "reply1": "Mulainya simpel: Google Business Profile dioptimasi, konten jawab pertanyaan calon pelanggan, review dibales rutin. Itu udah langkah besar buat usaha lokal.",
        "reply2": "Saya tulis panduan lengkapnya — dari nol sampe muncul di Google. Buat yang penasaran, di sini: https://studiosoft.id/seo-untuk-umkm/",
    },
    {
        "theme": "artikel ai marketing",
        "post": "{greet} Pertanyaan yang sering masuk: 'AI bakal gantiin marketer, nggak?' Jawaban jujur: yang diganti bukan marketingnya, tapi marketer yang nolak belajar AI.",
        "reply1": "Di 2026, AI udah dipake buat riset pasar, personalisasi iklan, sampe prediksi perilaku pelanggan. Yang nggak ikut belajar, pelan-pelan ninggalin.",
        "reply2": "Saya bahas tuntas — contoh nyata & cara mulainya. Penasaran? Baca: https://studiosoft.id/ai-untuk-marketing/",
    },
    {
        "theme": "artikel ai overview",
        "post": "{greet} AI Overview Google makin sering muncul, dan ini ngubah cara orang cari info. Kabar baiknya: peluang masih terbuka buat yang duluan nyadar. Kabar jeleknya: yang nggak nyadar, bakal ditinggal.",
        "reply1": "Kuncinya: konten yang langsung jawab, struktur rapi, dan sumber jelas. AI search suka yang bisa dikutip langsung sebagai jawaban.",
        "reply2": "Saya jelasin dari nol — apa itu AI Overview dan kenapa bisnis wajib tahu. Baca: https://studiosoft.id/apa-itu-ai-overview-google-kenapa-bisnis-surabaya-wajib-tahu/",
    },
    {
        "theme": "artikel strategi 2026",
        "post": "{greet} Strategi digital marketing yang dulu 'wajib', sekarang bisa jadi 'buang waktu'. Algoritma berubah, AI search makin dominan, perilaku pengguna geser. Yang nggak update, bakal main dengan peta lama.",
        "reply1": "Sekarang fokusnya: konten yang jawab niat pencarian, kehadiran di AI search, dan keputusan yang beneran berdasarkan data. Bukan sekadar rajin posting.",
        "reply2": "Saya rangkum strategi yang relevan tahun ini — lengkap dengan alasannya. Mau baca: https://studiosoft.id/strategi-digital-marketing-2026/",
    },

    # ── AWARENESS ARTIKEL DMARK (dmark.id — personal branding & creative) ──
    {
        "theme": "artikel dmark brand awareness",
        "post": "{greet} Banyak pemilik bisnis mikir: 'brand awareness itu buat perusahaan gede.' Padahal justru bisnis kecil yang paling diuntungkan — orang beli karena kenal & percaya, bukan karena banyak iklan.",
        "reply1": "Brand awareness itu fondasi: kalau orang nggak inget kamu, susah diajak transaksi. Mulai dari konsisten tampil, kasih nilai, dan tampil di tempat yang bener.",
        "reply2": "Saya tulis panduan langkah demi langkahnya — cocok banget buat pemilik UMKM. Penasaran? Baca: https://www.dmark.id/membangun-brand-awareness-umkm/",
    },
    {
        "theme": "artikel dmark branding otomasi",
        "post": "{greet} Dulu branding dan otomasi dianggep dua hal yang beda jauh. Padahal keduanya justru duet paling manjur: branding bikin orang inget, otomasi bikin bisnismu jalan terus tanpa bikin kamu kewalahan.",
        "reply1": "Bayangin: pesan yang sama terkirim konsisten ke semua pelanggan, sementara kamu fokus mikirin strategi. Itu yang bikin bisnis kecil bisa tumbuh kayak yang gede.",
        "reply2": "Saya bahas gimana dua-duanya dipaduin biar bisnis tumbuh lebih cepat. Mau baca: https://www.dmark.id/branding-dan-otomasi-duet-strategis/",
    },
    {
        "theme": "artikel dmark guerilla marketing",
        "post": "{greet} Bisnis kecil modal terbatas? Jangan sedih — justru di sini kreativitas yang jadi senjata. Guerilla marketing itu ngasih hasil gede tanpa budget gede, asal idenya ngena.",
        "reply1": "Kuncinya satu: bikin orang berhenti sebentar, terus penasaran. Nggak perlu gedung-gedung besar — cukup cara yang nggak biasa dan pas di telinga calon pelanggan.",
        "reply2": "Saya kumpulin 7 cara kreatif yang udah terbukti buat UMKM bersaing. Inspiratif banget: https://www.dmark.id/guerilla-marketing-umkm-cara-kreatif-bersaing/",
    },
    {
        "theme": "artikel dmark brand identity",
        "post": "{greet} Banyak yang salah pasang: logo doang dianggep udah jadi brand. Padahal brand identity itu lebih dari itu — cara kamu ngomong, tampil, dan bikin orang ngerasa. Itu yang bikin beda di pasar yang rame.",
        "reply1": "Pelanggan nggak inget logo doang — mereka inget perasaan. Brand yang konsisten dari warna sampe nada bicara, itu yang gampang diinget & dipercaya.",
        "reply2": "Ada 7 panduan lengkap yang bisa langsung kamu terapin. Buat yang serius bangun bisnis: https://www.dmark.id/panduan-lengkap-membangun-brand-identity-bisnis/",
    },

    {
        "theme": "artikel dmark logo",
        "post": "{greet} Logo itu sering dianggep remeh — 'yang penting ada'. Padahal logo yang bagus itu investasi: kesan pertama yang bikin orang inget & percaya sama bisnismu, dalam sekejap.",
        "reply1": "Logo yang jelek bisa bikin bisnis bagus keliatan nggak profesional. Sebaliknya, logo yang pas bikin pelanggan ngerasa 'ini brand yang serius'.",
        "reply2": "Kenapa logo itu investasi dan bukan cuma pengeluaran — saya bahas lengkap. Baca: https://www.dmark.id/desain-logo-profesional-investasi-visual-yang-tidak-boleh-asal-asalan/",
    },
    {
        "theme": "artikel dmark fotografi produk",
        "post": "{greet} Online shop, dengerin: foto produk itu 80% dari keputusan beli. Foto yang bagus bikin orang berhenti scroll & mikir 'ini keren'. Foto yang asal-asalan, sebaik apa pun produknya, susah laku.",
        "reply1": "Nggak perlu kamera mahal — exposure bagus, latar bersih, dan sudut yang nampilin kelebihan produk udah cukup buat mulai. Konsistensi juga kunci.",
        "reply2": "Saya kumpulin 10 tips jitu biar foto produk laris manis di online shop. Langsung kepake: https://www.dmark.id/fotografi-produk-tips-menampilkan-produk-agar-laris-online-shop/",
    },
    {
        "theme": "artikel studiosoft data driven",
        "post": "{greet} Banyak bisnis putusin strategi berdasarkan 'rasa' — padahal keputusan berdasarkan data itu jauh lebih tajam. Nggak perlu ribet: cukup ukur berapa yang lihat, klik, sama beli.",
        "reply1": "Dari 3 angka itu aja kamu udah bisa bikin keputusan lebih pintar dari kebanyakan kompetitor yang cuma nebak-nebak.",
        "reply2": "Saya bahas gimana data bisa nganterin bisnis tumbuh — pendekatan yang beneran kerja. Mau baca: https://studiosoft.id/strategi-digital-marketing-data-driven/",
    },

    # ── PERSONAL BRANDING (opini & wawasan — awareness, bukan jualan) ──
    {
        "theme": "pb aset bukan pamer",
        "post": "{greet} Personal branding sering dianggep cuma pamer atau buat seleb. Padahal justru sebaliknya: ini cara bikin orang inget kamu karena NILAI yang kamu kasih, bukan karena kamu pamer. Kepercayaan itu aset yang nggak bisa dibeli dengan iklan.",
        "reply1": "Orang beli dari yang mereka kenal, sukai, dan percaya. Ketika kamu sebagai pribadi udah dipercaya, bisnis & brand kamu ikut kebawa naik.",
        "reply2": "Mulai dari 1 bidang yang kamu kuasai beneran. Konsisten kasih value di situ, dan lama-lama orang bakal inget kamu sebagai 'yang ngerti soal itu'.",
    },
    {
        "theme": "pb konsisten kunci",
        "post": "{greet} Personal branding nggak dibangun sekali jadi — dia tumbuh dari repetisi kecil yang konsisten. Tampil rutin, bilang jelas, kasih nilai yang sama tiap kali. Orang mulai percaya karena kamu BISA DITEBAK: jelas apa yang kamu perjuangkan.",
        "reply1": "Konsistensi > intensitas. Lebih baik 3 konten bagus tiap minggu selama setahun, daripada 30 konten sebulan terus hilang.",
        "reply2": "Orang percaya sama yang bisa dipercaya — dan kepercayaan itu lahir dari konsisten, bukan dari sekali hantam yang spektakuler.",
    },
    {
        "theme": "pb spesialisasi",
        "post": "{greet} Banyak yang mikir biar 'keren' harus bisa ngomongin semua hal. Padahal justru sebaliknya: personal branding yang kuat itu SEMPIT tapi DALAM — kamu dikenal karena 1 hal yang kamu kuasai banget, bukan 10 hal yang kamu tahu setengah-setengah.",
        "reply1": "Lebih baik jadi 'raja di kotak kecil' daripada 'pemain biasa di lapangan besar'. Spesialisasi itu yang bikin orang nyari kamu.",
        "reply2": "Pilih 1 niche yang kamu suka & ada permintaannya. Fokus dalam-dalam 1-2 tahun, baru melebar kalau udah solid.",
    },
    {
        "theme": "pb autentik menang",
        "post": "{greet} Di era yang makin rame, orang pinter banget nebak mana yang asli dan mana yang diatur-atur. Personal branding yang menang bukan yang paling gagah, tapi yang paling AUTENTIK — berani tampil apa adanya, jujur soal proses.",
        "reply1": "Keaslian bikin orang ngerasa 'aku bisa nyambung sama dia'. Dari situ tumbuh koneksi yang jauh lebih kuat daripada sekadar citra yang dipoles.",
        "reply2": "Nggak perlu sempurna. Orang lebih inget yang relate daripada yang tampak nggak ada cacatnya.",
    },

    # ── KONTROVERSIAL & TANYA (bikin debat sehat / respon) ──
    {
        "theme": "kontroversial seo mati",
        "post": "{greet} Statement kontroversial: SEO 'cara lama' mulai mati. Keyword stuffing, backlink massal, konten tipis — sekarang itu malah bikin dihukum algoritma. Berani debat?",
        "reply1": "SEO yang bertahan: yang ngerti niat pengguna, bikin konten yang beneran menjawab, dan dibangun kayak manusia — bukan nurutin rumus lama.",
        "reply2": "Justru karena 'SEO mati', peluang makin gede buat yang serius. Yang males adaptasi bilang mati; yang belajar, menang diam-diam.",
    },
    {
        "theme": "tanya seo vs iklan",
        "post": "{greet} Polling buat pemilik bisnis: budget cuma cukup buat satu — iklan berbayar yang instan tapi berhenti pas budget habis, atau SEO yang mulai kerasa 3-6 bulan tapi efeknya panjang? Jawab A/B di komentar!",
        "reply1": "Jawaban saya: dua-duanya idealnya jalan bareng. Tapi kalau terpaksa satu — mulai dari SEO buat fondasi, sisakan sedikit buat iklan biar ada hasil cepat.",
        "reply2": "Iklan itu sewa pelanggan, SEO itu beli aset. Sewa boleh buat jalan dulu, tapi kalau nggak pernah beli rumah, selamanya bayar sewa.",
    },
    {
        "theme": "tanya pemakaian ai",
        "post": "{greet} Tanya-jawab: siapa yang udah rutin pakai AI buat kerjaan sehari-hari? Yang masih ragu, takutnya apa? Saya jujur: AI udah nghemat berjam-jam waktu saya tiap minggu — tapi tetep saya awasin. Cerita di komentar!",
        "reply1": "Kunci pakai AI yang bener: biarin AI yang ngerjain yang berat & berulang, manusia yang pegang strategi dan keputusan. Bukan sebaliknya.",
        "reply2": "Yang takut digantikan AI justru yang paling berisiko — karena yang dicari perusahaan itu orang yang bisa kerja sama sama AI, bukan yang nolaknya.",
    },
    {
        "theme": "tanya umur website",
        "post": "{greet} Polling singkat: website bisnismu terakhir dibikin/rombak kapan? 1) Kurang dari setahun 2) 1-3 tahun lalu 3) Lebih dari 3 tahun 4) Belum punya. Jawab nomornya — saya kasih saran sesuai kondisi!",
        "reply1": "Website di atas 3 tahun tanpa perombakan biasanya mulai ditinggal Google: desain lama, loading lambat, nggak mobile-friendly. Itu bikin calon pelanggan kabur diam-diam.",
        "reply2": "Website itu bukan barang sekali jadi — aset yang perlu dirawat: konten baru, kecepatan, keamanan. Kayak toko fisik yang perlu dirapiin.",
    },
]

# ==================== HELPERS ====================
def log(msg):
    with open(LOG_FILE, "a") as f:
        f.write(f"[{datetime.now(WIB).strftime('%Y-%m-%d %H:%M:%S')} WIB] {msg}\n")
    print(msg)


def load_json(path, default):
    if os.path.exists(path):
        try:
            with open(path) as f:
                return json.load(f)
        except Exception:
            return default
    return default


def save_json(path, data):
    with open(path, "w") as f:
        json.dump(data, f, indent=2)


def http_get(path):
    req = urllib.request.Request(BASE + path, headers=HEADERS)
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.loads(r.read())


def check_link(url):
    """Cek link nyala (200 OK) — aturan fix: link mati = konten tidak boleh dikirim."""
    try:
        req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}, method="GET")
        with urllib.request.urlopen(req, timeout=20) as r:
            return r.status == 200
    except Exception:
        return False


def validate_text(text, label="Tweet"):
    """Validasi ketat: maks 280 karakter + semua link dicek 200. JANGAN dipotong."""
    text = text.strip()
    if len(text) > MAX_CHARS:
        raise ValueError(f"{label} {len(text)} karakter > {MAX_CHARS} — JANGAN dipotong, ringkas dulu.")
    if not text:
        raise ValueError(f"{label} kosong.")
    # Cek semua link di teks
    for url in re.findall(r'https?://[^\s]+', text):
        url = url.rstrip('.,;!?')
        if not check_link(url):
            raise ValueError(f"{label} punya link mati: {url}")
    return text


def pick_fresh_theme(used_hashes):
    """Ambil tema yang belum pernah dipakai (hash unik)."""
    for theme in THEMES:
        h = hashlib.md5(theme["theme"].encode()).hexdigest()
        if h not in used_hashes:
            return theme, h
    return None, None


def render(text, greeting):
    return text.replace("{greet}", greeting)


def append_cta(text):
    """Tambahkan CTA otomatis di akhir tweet kalau muat (<=280) & tidak ada link.
    Skip kalau sudah ada tanda tanya atau kata 'komentar' — biar tidak dobel ajakan."""
    if "http://" in text or "https://" in text:
        return text  # jangan tempel CTA setelah link
    if "?" in text or "komentar" in text.lower():
        return text  # sudah ada ajakan bicara
    base = text.rstrip()
    for cta in random.sample(CTA_BANK, len(CTA_BANK)):
        candidate = base + " " + cta
        if len(candidate) <= MAX_CHARS:
            return candidate
    return text


def get_schedules_today():
    """Ambil semua jadwal hari ini (UTC) untuk akun Twitter.
    API list mengabaikan filter accountId → fetch pending + success, filter manual."""
    today_utc = datetime.now(timezone.utc).strftime("%Y-%m-%d")
    out = []
    for status in ("pending", "success"):
        for page in range(1, 10):
            try:
                d = http_get(f"/public/schedule?page={page}&limit=50&status={status}")
            except Exception as e:
                log(f"⚠️ Gagal fetch schedule {status} page {page}: {e}")
                break
            batch = d.get("docs", [])
            for x in batch:
                if x.get("accountId") != ACCOUNT_ID:
                    continue
                sched = x.get("scheduleAt", "")
                if sched.startswith(today_utc):
                    out.append(x)
            if len(batch) < 50:
                break
    return out


def get_pending_slot(schedules_today):
    """Slot kosong berikutnya: urutkan jam schedule hari ini, cari jam WIB yang belum ada."""
    used_hours = set()
    for x in schedules_today:
        sched = x.get("scheduleAt", "")
        try:
            dt = datetime.strptime(sched, "%Y-%m-%dT%H:%M:%S.000Z")
            dt = dt.replace(tzinfo=timezone.utc) + timedelta(hours=7)  # → WIB
            used_hours.add(dt.hour)
        except Exception:
            continue
    now_wib = datetime.now(WIB)
    for i, hour in enumerate(SLOT_HOURS):
        if hour in used_hours:
            continue
        # Jangan isi slot yang jamnya sudah lewat (kecuali sudah lewat semua → besok)
        if hour > now_wib.hour or (hour == now_wib.hour and now_wib.minute < 30):
            return i
    # Semua slot terisi hari ini
    return None


def post_nested(texts, slot_hour):
    """Post nested: Post 1 → Reply 2 → Reply 3, jeda 1 menit, jam WIB slot_hour."""
    today = datetime.now(WIB).strftime("%Y-%m-%d")
    parent_id = None
    ids = []
    for i, text in enumerate(texts):
        wib_dt = datetime.strptime(f"{today}T{slot_hour:02d}:{i:02d}:00", "%Y-%m-%dT%H:%M:%S")
        iso_utc = (wib_dt - timedelta(hours=7)).strftime("%Y-%m-%dT%H:%M:%S.000Z")

        payload = {
            "accountId": ACCOUNT_ID,
            "title": "",
            "description": text,
            "topic": "SEO" if i == 0 else "",
            "type": "text",
            "medias": [],
            "scheduleAt": iso_utc,
            "replies": [parent_id] if parent_id else [],
        }
        body = json.dumps(payload).encode()
        req = urllib.request.Request(f"{BASE}/public/schedule", data=body, headers=HEADERS, method="POST")
        try:
            with urllib.request.urlopen(req, timeout=30) as r:
                result = json.loads(r.read())
                sid = result.get("scheduleId", result.get("id", "?"))
                ids.append(sid)
                parent_id = sid
                log(f"✅ Tweet {i+1} → {sid} | {slot_hour:02d}:{i:02d} WIB")
        except urllib.error.HTTPError as e:
            err = e.read().decode()
            log(f"❌ Tweet {i+1}: HTTP {e.code} — {err[:200]}")
            raise
    return ids


def main():
    now_str = datetime.now(WIB).strftime("%Y-%m-%d %H:%M WIB")
    print("=" * 60)
    print(f"🐦 TWITTER @UkyHandoko — 7 SLOT NESTED POSTING (GAYA NGOMONGIN)")
    print(f"   {now_str}")
    print("=" * 60)

    # 1. Cek slot kosong dari API Repliz (bukan tracker lokal — sesuai permintaan Bos)
    scheds = get_schedules_today()
    slot_idx = get_pending_slot(scheds)
    if slot_idx is None:
        print("   ⚠️  Semua slot hari ini sudah terisi. Selesai.")
        return
    slot_wib = SLOT_WIB[slot_idx]
    print(f"   🎯 Slot kosong berikutnya: {slot_wib} WIB")

    # 2. Pilih tema unik
    used_hashes = load_json(THEME_TRACK_FILE, {})
    theme, h = pick_fresh_theme(used_hashes)
    if not theme:
        print("   ⚠️  Semua tema sudah terpakai — perlu tambah konten baru. Selesai.")
        return
    print(f"   📌 Tema: {theme['theme']}")

    # 3. Render & validasi (maks 280 karakter + link 200)
    greeting = random.choice(GREETINGS)
    texts = [render(theme["post"], greeting), theme["reply1"], theme["reply2"]]
    texts = [append_cta(t) for t in texts]  # CTA otomatis (FIXED 12 Agustus 2026)
    validated = []
    for i, t in enumerate(texts):
        try:
            validated.append(validate_text(t, label=f"Tweet {i+1}"))
        except ValueError as e:
            log(f"SKIP: {e}")
            return

    # 4. Kirim nested
    try:
        ids = post_nested(validated, SLOT_HOURS[slot_idx])
    except Exception as e:
        log(f"❌ Gagal posting: {str(e)[:150]}")
        return

    # 5. Simpan tracker (anti duplikasi)
    used_hashes[h] = {"theme": theme["theme"], "posted": datetime.now(WIB).strftime("%Y-%m-%d %H:%M")}
    save_json(THEME_TRACK_FILE, used_hashes)
    print(f"   💾 Tema '{theme['theme']}' ditandai sudah terpakai")

    print("=" * 60)
    print("✅ Selesai — Nested 3 tweet terkirim ke slot", slot_wib, "WIB")
    print("=" * 60)


if __name__ == "__main__":
    main()
