#!/usr/bin/env python3
"""
Threads Cross Mention Engine — akun Threads kita saling mention & saling reply (chain).
Setiap run: jadwalkan 3 pasangan (poster → replier) yang paling lama belum dipakai,
jadwalkan post mention + nested reply berantai 3-4 balasan (maks 5 level) lewat Repliz.
Jalan via cron tiap 6 jam (3 interaksi/run = 12 interaksi/hari, rotasi merata semua akun).

Tujuannya:
- Akun-akun kita saling mention (interaksi terlihat natural di Threads).
- Tiap interaksi jadi percakapan berantai: mention → reply → tanggapan → dst (3-4 kali,
  maksimal 5 level), bergantian antar dua akun. HANYA antar akun internal Repliz.

Aturan (FIXED 4-5 Agustus 2026, update 18 Agustus 2026):
- Bahasa humanis, sambutan positif, pakai "saya".
- Rotasi pasangan adil: akun yang paling lama belum jadi poster → poster duluan,
  1 akun maksimal 1x jadi poster & 1x jadi replier dalam 1 run.
- Tracker biar gak duplikat & gak spam akun yang sama.
"""
import sys, json, os, time, random
from datetime import datetime, timedelta, timezone
import urllib.request, urllib.error
sys.path.insert(0, "/home/mantapman/.hermes/profiles/atun/workspace")
from repliz_client import HEADERS, BASE
from threads_text_check import cek_teks_threads, ThreadsTextError

# ── Semua akun Threads (user=None → jangan mention di teks, cukup reply) ──
AKUN = {
    "uky":     {"id": "6a334e89c5ff4ce3a3225a48", "user": "@ukyhandoko"},
    "ss":      {"id": "6a335b9ec5ff4ce3a3225c2a", "user": "@studiosoft.id"},
    # LEIT DIKELUARKAN 24 Agu 2026 (instruksi Bos): akun Threads LEIT HANYA posting caption,
    # TIDAK ikut reply/diskusi/comment — jangan dimasukkan lagi ke mesin ini.
    "tslaw":   {"id": "6a35f8b7c5ff4ce3a322b2ed", "user": "@tslaw"},
    "tsc":     {"id": "6a4bbc5920e4f4f195e52960", "user": "@dniclinic_krian"},
    "das":     {"id": "6a39e461c5ff4ce3a3233e09", "user": "@das_bengkel"},
    # DMARK tidak punya akun Threads (cuma IG, LinkedIn, FB) — 7 Agu 2026,
    # dihapus dari cross-mention Threads karena ID-nya not found di Repliz.
    "everybe": {"id": "6a44ed1920e4f4f195d8ecf7", "user": None},
}

TRACKER = "/home/mantapman/.hermes/profiles/atun/workspace/.threads_cross_mention_tracker.json"
MAX_REPLY_CHARS = 480
PAIRS_PER_RUN = 3  # jumlah interaksi (poster→replier) per run

# ── Kumpulan teks mention (poster → mention replier) ──
MENTION_TEXTS = [
    "Baru aja ngobrol soal strategi digital, dan {user} selalu punya sudut pandang yang menarik. Menurut kamu, apa hal paling underrated yang sering dilupakan bisnis kecil? \U0001F440",
    "Satu hal yang saya pelajari akhir-akhir ini: konsistensi itu segalanya. {user} pasti setuju — apa rahasia kalian tetap konsisten? \U0001F4AA",
    "Kadang solusi paling simpel justru paling jarang dilirik. {user}, dari pengalamanmu, apa satu hal simpel yang dampaknya gede banget? \U0001F914",
    "Saya percaya kolaborasi itu bikin semua orang maju lebih cepat. {user} — apa sih yang paling kamu nikmati dari kerja di bidangmu? \U0001F64C",
    "Belajar dari orang yang lebih dulu jalan itu shortcut terbaik. {user}, satu nasihat yang bakal kamu kasih ke yang baru mulai? \U0001F680",
    "Hari ini saya lagi mikir: teknologi canggih itu percuma kalau orangnya gak mau adaptasi. {user}, menurut kamu skill apa yang paling penting buat tetap relevan ke depan? \U0001F4A1",
    "Pernah dengar istilah \"belajar sambil jalan\"? {user} itu contoh nyatanya. Ada gak sih satu kegagalan yang justru jadi pelajaran paling berharga buatmu? \U0001F914",
    "Yang bikin usaha berkembang itu bukan cuma modal, tapi juga cara pandang. {user}, kalo boleh tahu, kebiasaan apa yang paling membantu pertumbuhan kalian? \U0001F331",
    "Sering ditanya, \"mulai dari mana?\" {user} — kalau disuruh milih satu langkah pertama buat yang baru mulai, apa jawabanmu? \U0001F680",
    "Kolaborasi antar bidang itu menarik banget. {user}, menurutmu apa yang bisa kita pelajari dari satu sama lain? \U0001F64C",
]

# ── Kumpulan reply (replier → balas mention poster) ──
REPLY_TEXTS = [
    "Makasih udah mention! \U0001F64F Satu hal paling underrated menurut saya: evaluasi rutin. Banyak yang rajin mulai tapi jarang mengevaluasi progresnya.",
    "Siap setuju! Konsistensi emang kunci. Rahasia saya: jadwal rutin + target kecil yang realistis. Pelan tapi pasti. \U0001F680",
    "Halo! Makasih udah ajak diskusi. \U0001F60A Menurut saya: dengarkan pelanggan langsung. Data penting, tapi suara pelanggan itu kompas paling jujur.",
    "Senang banget bisa diajak ngobrol! \U0001F64C Yang paling saya nikmati: melihat ide yang tadinya cuma wacana akhirnya jalan dan berdampak. Itu kepuasan tersendiri.",
    "Nasihat saya satu: jangan takut mulai dari kecil. \U0001F331 Konsisten + mau belajar = hampir semua hal bisa dicapai. Makasih ya, diskusi ini seru!",
    "Setuju banget sama poin kamu! \U0001F64C Justru momen kayak gini yang bikin ekosistem kita makin sehat. Sukses terus untuk kita semua! \U0001F525",
    "Pertanyaan bagus! \U0001F914 Kalau menurut saya: jangan pernah berhenti belajar. Dunia berubah cepat, yang adaptif yang bertahan. Makasih udah ajak mikir bareng! \U0001F60A",
    "Wah, makasih banyak! \U0001F64F Pelajaran paling berharga buat saya: kegagalan itu data. Selama masih mau dievaluasi dan dicoba lagi, itu bukan akhir. \U0001F4AA",
    "Kebiasaan yang paling ngebantu: mulai hari dengan prioritas paling penting dulu. Sisanya ngikut. Simpel tapi efeknya besar! \U0001F4C5",
    "Satu langkah pertama: pahami dulu masalah yang mau diselesaikan. Setelah itu baru cari solusi. Kebanyakan orang kebalik, makanya gampang nyerah. \U0001F680",
    "Justru itu serunya! \U0001F64C Saya yakin kita bisa saling melengkapi — cara pandang yang beda itu yang bikin kolaborasi jadi kaya. Makasih sudah memulai obrolan ini! \U0001F525",
]

# ── Follow-up replies (level 2-4) — tanggapan lanjutan biar chain natural ──
FOLLOWUP_TEXTS_1 = [
    "Makasih jawabannya, insightful banget! \U0001F64F Saya setuju — hal simpel yang dijalanin konsisten justru paling berdampak.",
    "Setuju banget sama jawabanmu! \U0001F44F Justru dari obrolan kayak gini saya jadi inget: jangan pernah remehin langkah kecil.",
    "Wah, jawaban yang bikin mikir. \U0001F914 Ini yang saya suka dari diskusi — tiap orang punya cara pandang yang beda.",
    "Betul! Kadang kita terlalu fokus ke hal besar, padahal yang kecil dan rutin itu yang bikin beda. Makasih ya sudah berbagi! \U0001F49B",
    "Nah, ini penting banget. \U0001F4AA Saya catat nih — semoga makin banyak yang terinspirasi dari perspektifmu.",
]

FOLLOWUP_TEXTS_2 = [
    "Justru seru kalau gitu! \U0001F60A Semoga obrolan kecil kayak gini bisa nambah energi positif buat siapa pun yang baca.",
    "Haha iya, diskusi santai begini kadang lebih nyantol daripada materi formal. \U0001F64C Makasih sudah ngobrol bareng!",
    "Siap, semoga insight ini berguna buat yang lagi mulai juga. \U0001F680 Kolaborasi emang bikin semua makin cepat berkembang.",
    "Setuju! \U0001F525 Yang penting saling support dan saling belajar. Semoga kita makin solid ke depannya.",
    "Nah itu dia! \U0001F4A1 Senang banget bisa diskusi kayak gini. Sampai ketemu di obrolan berikutnya ya!",
]

FOLLOWUP_TEXTS_3 = [
    "Diskusi yang seru banget! \U0001F64C Semoga obrolan ini bermanfaat buat yang baca juga. Sampai jumpa di obrolan berikutnya!",
    "Makasih sudah meluangkan waktu ngobrol! \U0001F64F Ini jadi pengingat kalau belajar bisa dari mana aja — termasuk dari obrolan santai.",
    "Oke, obrolan yang menyenangkan! \U0001F60A Tetap semangat dan sukses terus buat kita semua!",
    "Seru! \U0001F680 Saya jadi tambah semangat setelah ngobrol ini. Semoga kita makin sering kolaborasi ke depannya.",
    "Noted semua poinnya! \U0001F4D1 Sampai jumpa di diskusi berikutnya. Sukses terus buat kita semua, dan semoga obrolan ini bermanfaat! \U0001F525",
]

# ── Template reply kalo user replier gak dikenal (dipakai juga) ──
def load_tracker():
    if os.path.exists(TRACKER):
        try:
            with open(TRACKER) as f:
                return json.load(f)
        except Exception:
            return {}
    return {}


def save_tracker(t):
    with open(TRACKER, "w") as f:
        json.dump(t, f, indent=2)


def schedule_chain(poster_id, post_text, schedule_at, chain):
    """Schedule post + nested replies lintas akun (chain multi-level).

    chain: list of (account_id, text) untuk reply 1, 2, 3, ...
    Pola TERBUKTI (test 18 Agu 2026): tiap entri dijadwalkan terpisah,
    replies=[parent_id] → membentuk nested chain lintas akun.
    Jadwal: post X:00, reply1 X:01, reply2 X:02, dst.
    """
    base = datetime.fromisoformat(schedule_at.replace("Z", "+00:00"))
    ids = []
    parent = None

    def _sched(account_id, text, at_iso):
        payload = {
            "accountId": account_id,
            "title": "Cross Mention",
            "description": text,
            "topic": "",
            "type": "text",
            "medias": [],
            "meta": {"title": "", "description": "", "url": ""},
            "additionalInfo": {
                "isAiGenerated": False, "isDraft": False,
                "collaborators": [], "mentions": [],
                "music": {"id": "", "artist": "", "name": "", "thumbnail": ""},
                "products": [], "tags": []
            },
            "replies": [parent] if parent else [],
            "scheduleAt": at_iso,
        }
        req = urllib.request.Request(
            BASE + "/public/schedule",
            data=json.dumps(payload).encode(),
            headers={**HEADERS, "Content-Type": "application/json"},
            method="POST",
        )
        with urllib.request.urlopen(req, timeout=30) as r:
            return json.loads(r.read())

    # Post utama
    res = _sched(poster_id, post_text, base.strftime("%Y-%m-%dT%H:%M:%S.000Z"))
    sid = res.get("scheduleId") or res.get("_id") or res.get("id")
    if not sid:
        raise RuntimeError(f"Post gagal: {str(res)[:200]}")
    ids.append(sid)
    parent = sid

    # Nested replies berurutan
    for i, (acc, text) in enumerate(chain, start=1):
        at_iso = (base + timedelta(minutes=i)).strftime("%Y-%m-%dT%H:%M:%S.000Z")
        res = _sched(acc, text, at_iso)
        sid = res.get("scheduleId") or res.get("_id") or res.get("id")
        if not sid:
            raise RuntimeError(f"Reply {i} gagal: {str(res)[:200]}")
        ids.append(sid)
        parent = sid

    return ids


def pick_pairs(tracker, n=PAIRS_PER_RUN):
    """Pilih n pasangan (poster, replier) unik — semua akun rotasi adil.

    Prioritas:
    - Akun yang paling lama belum jadi poster → dipilih jadi poster duluan.
    - Replier dipilih yang paling lama belum kepasangan dengan poster tsb.
    - Dalam 1 run: 1 akun maksimal 1x jadi poster & 1x jadi replier (biar merata).
    """
    keys = list(AKUN.keys())
    last_used = tracker.get("last_used", {})
    last_poster = tracker.get("last_poster", {})

    def pair_score(a, b):
        return last_used.get(f"{a}->{b}", 0)

    # calon poster: urut dari yang paling lama belum jadi poster
    posters = sorted(keys, key=lambda k: last_poster.get(k, 0))
    pairs = []
    used_poster, used_replier = set(), set()

    for poster_key in posters:
        if len(pairs) >= n:
            break
        if poster_key in used_poster:
            continue
        cands = [b for b in keys if b != poster_key and b not in used_replier]
        if not cands:
            continue
        cands.sort(key=lambda b: pair_score(poster_key, b))
        replier_key = cands[0]
        pairs.append((poster_key, replier_key))
        used_poster.add(poster_key)
        used_replier.add(replier_key)
    return pairs


def main():
    tracker = load_tracker()
    now = datetime.now(timezone.utc)
    pairs = pick_pairs(tracker, PAIRS_PER_RUN)
    if not pairs:
        print("Tidak ada pasangan yang tersedia.")
        sys.exit(1)

    print(f"Cross mention: {len(pairs)} interaksi akan dijadwalkan")
    for i, (poster_key, replier_key) in enumerate(pairs):
        poster = AKUN[poster_key]
        replier = AKUN[replier_key]

        # Jadwal: +3h, +4h, +5h dari sekarang (bulat ke jam berikutnya)
        sched = (now + timedelta(hours=3 + i)).replace(minute=0, second=0, microsecond=0)
        sched_iso = sched.strftime("%Y-%m-%dT%H:%M:%S.000Z")

        # Teks mention: pakai @user kalau tersedia, tanpa mention kalau tidak
        if poster["user"] and replier["user"]:
            post_text = random.choice(MENTION_TEXTS).format(user=replier["user"])
        else:
            post_text = random.choice([
                "Satu hal yang saya pelajari akhir-akhir ini: konsistensi itu segalanya. Apa rahasia kalian tetap konsisten? \U0001F4AA",
                "Kadang solusi paling simpel justru paling jarang dilirik. Dari pengalamanmu, apa satu hal simpel yang dampaknya gede banget? \U0001F914",
                "Saya percaya kolaborasi itu bikin semua orang maju lebih cepat. Apa sih yang paling kamu nikmati dari kerja di bidangmu? \U0001F64C",
            ])

        # Chain reply: 3-4 balasan (total level maks 5: post + 4 reply)
        depth = random.randint(3, 4)
        chain = []
        # Reply 1: replier menjawab mention
        chain.append((replier["id"], random.choice(REPLY_TEXTS)))
        # Reply 2: poster menanggapi
        chain.append((poster["id"], random.choice(FOLLOWUP_TEXTS_1)))
        # Reply 3: replier menanggapi lagi
        chain.append((replier["id"], random.choice(FOLLOWUP_TEXTS_2)))
        # Reply 4 (jika depth=4): poster menutup
        if depth == 4:
            chain.append((poster["id"], random.choice(FOLLOWUP_TEXTS_3)))

        # VALIDASI KETAT (FIXED 5 Agustus 2026): max karakter + link nyala, JANGAN dipotong
        try:
            post_text = cek_teks_threads(post_text, label="Post Mention", maxlen=MAX_REPLY_CHARS)
            for j, (acc, txt) in enumerate(chain, start=1):
                chain[j - 1] = (acc, cek_teks_threads(txt, label=f"Reply {j}", maxlen=MAX_REPLY_CHARS))
        except ThreadsTextError as e:
            print(f"  SKIP {poster_key}->{replier_key}: {e}")
            continue

        print(f"Cross mention: {poster_key} -> {replier_key} @ {sched_iso} UTC (depth {depth})")
        print(f"  Post: {post_text[:100]}")
        for j, (acc, txt) in enumerate(chain, start=1):
            print(f"  Reply {j}: {txt[:100]}")

        try:
            ids = schedule_chain(poster["id"], post_text, sched_iso, chain)
            print(f"  \u2705 Terjadwal! IDs: {', '.join(ids)}")

            last_used = tracker.setdefault("last_used", {})
            last_poster = tracker.setdefault("last_poster", {})
            pair_key = f"{poster_key}->{replier_key}"
            last_used[pair_key] = int(time.time())
            last_poster[poster_key] = int(time.time())
            tracker["last_pair"] = [poster_key, replier_key]
            tracker.setdefault("history", []).append({
                "pair": pair_key,
                "at": sched_iso,
                "depth": depth,
                "schedule_ids": ids,
                "created": time.strftime("%Y-%m-%d %H:%M:%S"),
            })
            # simpan history maks 50
            tracker["history"] = tracker["history"][-50:]
            save_tracker(tracker)
        except urllib.error.HTTPError as e:
            print(f"  \u274C Gagal jadwal {poster_key}->{replier_key}: HTTP {e.code} {e.read().decode()[:200]}")
            continue
        except Exception as e:
            print(f"  \u274C Gagal jadwal {poster_key}->{replier_key}: {str(e)[:150]}")
            continue


if __name__ == "__main__":
    main()
