#!/usr/bin/env python3
"""
Threads Text Check — WAJIB dipakai sebelum kirim teks ke Threads.

Aturan (FIXED 5 Agustus 2026):
- Semua teks Threads wajib DIHITUNG dulu: maksimal 500 karakter.
- Kalau lebih dari 500 → JANGAN dikirim & JANGAN dipotong.
  Teks harus diperbaiki/diringkas dulu, baru dikirim utuh.
- Tidak boleh ada teks yang terpotong (truncate) di Threads.
- Kalau teks ada LINK → link WAJIB dicek: harus nyala (HTTP 200),
  bukan 404. Link mati = teks tidak boleh dikirim.
- Caption Threads WAJIB minimal 1 paragraf (teks non-link minimal
  MIN_PARAGRAPH_CHARS karakter) — JANGAN kirim caption yang cuma
  link doang atau satu baris tanpa pembahasan.
- Kalau teks ada LINK → WAJIB ada pembahasan SEBELUM link
  (minimal MIN_PREAMBLE_CHARS karakter teks dulu sebelum URL pertama).
  Link di awal caption tanpa pembahasan = TOLAK.

Pemakaian:
    from threads_text_check import cek_teks_threads, cek_link
    teks = cek_teks_threads(teks, label="Caption Threads")  # raise ThreadsTextError kalau > 500 atau link mati
    ok, info = cek_link("https://studiosoft.id/...")        # (True, "200 OK") / (False, "404 Not Found")
"""
import re
import urllib.error
import urllib.request

MAX_THREADS_CHARS = 500
MIN_PARAGRAPH_CHARS = 80   # minimal teks non-link ≈ 1 paragraf pendek
MIN_PREAMBLE_CHARS = 60    # minimal teks pembahasan SEBELUM link pertama
URL_RE = re.compile(r'https?://[^\s"\'\\\)\]\},;]+')


class ThreadsTextError(ValueError):
    """Teks Threads tidak lolos validasi — jangan kirim, perbaiki dulu."""


def hitung_karakter(teks: str) -> int:
    """Hitung panjang teks (len python — termasuk emoji sebagai 1 karakter per codepoint)."""
    return len(teks)


def cek_link(url: str, timeout: int = 20):
    """
    Cek apakah link nyala. Follow redirect otomatis.
    Return (True, "200 OK") kalau nyala; (False, alasan) kalau mati/error.
    """
    url = url.rstrip('.,;!?)')  # bersihkan tanda baca di ujung URL
    req = urllib.request.Request(
        url,
        headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},
    )
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            code = r.getcode()
            if 200 <= code < 400:
                return True, f"{code} OK"
            return False, f"HTTP {code}"
    except urllib.error.HTTPError as e:
        return False, f"HTTP {e.code} ({e.reason})"
    except urllib.error.URLError as e:
        return False, f"URL error: {str(e.reason)[:80]}"
    except Exception as e:
        return False, f"{type(e).__name__}: {str(e)[:80]}"


def cek_teks_threads(teks: str, label: str = "Teks Threads", maxlen: int = MAX_THREADS_CHARS) -> str:
    """
    Validasi lengkap teks Threads sebelum dikirim:
    1. Panjang harus ≤ maxlen (default 500) — kalau lebih, TOLAK (jangan potong).
    2. Semua link di dalam teks harus nyala (200 OK) — kalau ada yang mati, TOLAK.
    3. Caption minimal 1 paragraf — teks non-link minimal MIN_PARAGRAPH_CHARS karakter.
    4. Kalau ada link, WAJIB ada pembahasan sebelum link (minimal
       MIN_PREAMBLE_CHARS karakter teks sebelum URL pertama).
    Return teks apa adanya kalau lolos; raise ThreadsTextError kalau tidak.
    """
    teks = (teks or "").strip()
    n = hitung_karakter(teks)
    if n <= 0:
        raise ThreadsTextError(f"⛔ {label} kosong — tidak boleh dikirim.")

    if n > maxlen:
        raise ThreadsTextError(
            f"⛔ {label} TIDAK BOLEH dikirim: {n} karakter (maks {maxlen}). "
            f"Ringkas dulu sampai ≤ {maxlen}, JANGAN dipotong otomatis. "
            f"Teks: {teks[:120]}..."
        )

    # Cek semua link di teks
    urls = URL_RE.findall(teks)
    mati = []
    for u in urls:
        ok, info = cek_link(u)
        if not ok:
            mati.append((u, info))
    if mati:
        detail = "; ".join(f"{u[:70]} -> {info}" for u, info in mati[:3])
        raise ThreadsTextError(
            f"⛔ {label} punya LINK MATI ({len(mati)}): {detail}. "
            f"Perbaiki link dulu sebelum dikirim — jangan kirim link 404."
        )

    # ── Aturan baru: minimal 1 paragraf (teks non-link) ──
    teks_tanpa_url = URL_RE.sub(" ", teks)
    teks_tanpa_url = re.sub(r"\s+", " ", teks_tanpa_url).strip()
    if len(teks_tanpa_url) < MIN_PARAGRAPH_CHARS:
        raise ThreadsTextError(
            f"⛔ {label} BELUM 1 PARAGRAF ({len(teks_tanpa_url)} karakter non-link "
            f"< {MIN_PARAGRAPH_CHARS}). Tambah pembahasan dulu — jangan kirim caption "
            f"yang cuma link atau satu baris doang."
        )

    # ── Aturan baru: link wajib didahului pembahasan ──
    if urls:
        first_url = urls[0]
        pos = teks.find(first_url)
        pre = teks[:pos].strip() if pos >= 0 else ""
        if len(pre) < MIN_PREAMBLE_CHARS:
            raise ThreadsTextError(
                f"⛔ {label} LINK DI AWAL TANPA PEMBAHASAN ({len(pre)} karakter sebelum "
                f"link < {MIN_PREAMBLE_CHARS}). Tulis dulu minimal 1 kalimat pembahasan "
                f"tentang link-nya, baru tempel link-nya."
            )

    return teks


if __name__ == "__main__":
    import sys
    if len(sys.argv) < 2:
        print("Gunakan: python3 threads_text_check.py '<teks>' [label]")
        print("         python3 threads_text_check.py --link '<url>'")
        sys.exit(1)
    if sys.argv[1] == "--link":
        ok, info = cek_link(sys.argv[2])
        print(f"{'✅ LINK NYALA' if ok else '❌ LINK MATI'}: {sys.argv[2]} -> {info}")
        sys.exit(0 if ok else 2)
    label = sys.argv[2] if len(sys.argv) > 2 else "Teks"
    try:
        hasil = cek_teks_threads(sys.argv[1], label)
        print(f"✅ {label}: {len(hasil)} karakter — AMAN dikirim.")
    except ThreadsTextError as e:
        print(e)
        sys.exit(2)
