#!/usr/bin/env python3
"""Schedule FB DAS Bengkel Indonesia — 14 Sep 2026.

Cron fb-das-harian jalan 10:00 UTC = 17:00 WIB → slot 17:00 WIB sudah LEWAT saat script
jalan (preseden schedule_das_fb_20260901..13.py: semua tayang 13:00 UTC = 20:00 WIB).
Script memilih sendiri slot kosong PERTAMA hari ini yang masih di depan (>=10 menit) dari
7-slot WIB → hari ini = 20:00 WIB (13:00 UTC). (Slot 10:20Z hari ini sudah dipakai
das-short-daily = text post, pipeline berbeda.)

Artikel: https://dasindonesia.com/bengkel-mercy-surabaya
- Publish 2026-09-12 03:33, belum pernah dipakai di akun DAS FB (0 hit di semua status).
- Dicek dengan scan_das_unused2.py (diff artikel live vs link terpakai di
  post_das_fb_history.json + SELURUH jadwal akun DAS FB) → 147 kandidat bersih; dipilih
  yang paling fresh. Prompt menawarkan penyebab-mesin-mobil-overheat &
  kapan-mobil-perlu-engine-overhaul, tapi KEDUANYA SUDAH terpakai (16 Jul & 15/28 Jul/8 Sep).
- `bengkel-nissan-surabaya` dihindari (dipakai pipeline DAS Threads hari ini 23:00 WIB).

Format: image 1080x1350 (bg #1a1a2e, teks putih, aksen #f97316) + caption 4 paragraf + link +
pancingan diskusi (diskusi_engine otomotif tone netral).
Aturan DAS: NO kata harga/biaya/murah/mahal/hemat; 0 mention internal; 0 hashtag (pola Sep 2026);
FB TIDAK support replies → replies=[].
"""
import json, os, re, sys, subprocess, time, urllib.request, urllib.error
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo

from repliz_client import upload_image_to_server, HEADERS, BASE, ACC
import diskusi_engine

FB_DAS_ID = ACC.DAS_FB  # 6a3b41e1c5ff4ce3a327543e
HERE = os.path.dirname(os.path.abspath(__file__))
LOG_FILE = os.path.join(HERE, 'post_das_fb_history.json')
IMG_PATH = os.path.join(HERE, 'das_fb_20260914.png')
ARTICLE_URL = "https://dasindonesia.com/bengkel-mercy-surabaya"
TGL = "2026-09-14"

SLOTS_WIB = ['05:00', '08:00', '11:00', '14:00', '17:00', '20:00', '23:00']

# Pancingan diskusi dari diskusi_engine (industri otomotif, tone netral — rotasi dari
# 13 Sep yang pakai tone opini "Bold statement").
PANCINGAN = "Apa yang paling Anda pertimbangkan saat memilih bengkel? Share dong."
assert PANCINGAN in diskusi_engine.PANCINGAN['otomotif']['netral'], "pancingan bukan dari diskusi_engine"

CAPTION = """Mobil Mercedes-Benz jarang rusak mendadak. Yang lebih sering terjadi, keluhannya datang pelan-pelan: AC tidak sedingin dulu, setir terasa sedikit bergetar, atau bunyi halus dari area kaki-kaki yang kita anggap angin lalu.

Masalahnya, di Mercy semuanya saling terhubung. Satu lampu peringatan bisa berarti beberapa kemungkinan sekaligus, dari busi dan injektor sampai sensor di sistem rem dan suspensi adaptif. Di titik ini pengalaman dan alat diagnostik yang tepat jadi penentu — bukan coba-coba ganti komponen.

Kami rangkum gejala yang perlu diwaspadai, perawatan rutin yang wajib dijaga, sampai kebiasaan yang justru memperpendek umur komponen di artikel ini: """ + ARTICLE_URL + """

""" + PANCINGAN


def load_history():
    if os.path.exists(LOG_FILE):
        with open(LOG_FILE) as f:
            return json.load(f)
    return {'posts': []}


def is_duplicate(history, article_url):
    return any((p.get('article_url') or '').rstrip('/') == article_url.rstrip('/')
               for p in history['posts'])


def scan_account(day):
    """Semua jadwal akun DAS FB: (pending hari ini) + set link yang pernah dipakai + cek dobel artikel."""
    pend, used, same_article = [], set(), []
    page = 1
    while True:
        req = urllib.request.Request(f'{BASE}/public/schedule?page={page}&limit=100',
                                     headers=HEADERS, method='GET')
        with urllib.request.urlopen(req, timeout=60) as r:
            data = json.loads(r.read())
        for d in data.get('docs', []):
            if d.get('accountId') != FB_DAS_ID:
                continue
            desc = d.get('description') or ''
            for l in re.findall(r'https?://dasindonesia\.com[^\s]*', desc):
                used.add(l.rstrip('/'))
            if ARTICLE_URL in desc and d.get('status') in ('pending', 'draft', 'success'):
                same_article.append((d.get('status'), d.get('scheduleAt'), d.get('_id')))
            if d.get('status') in ('pending', 'draft') and (d.get('scheduleAt') or '').startswith(day):
                pend.append((d.get('scheduleAt'), d.get('_id')))
        if page >= data.get('totalPages', 1):
            break
        page += 1
    return pend, used, same_article


def pick_slot():
    """Slot 7-slot WIB pertama hari ini yang masih di depan (>=10 menit dari sekarang)."""
    now = datetime.now(ZoneInfo('Asia/Jakarta'))
    for s in SLOTS_WIB:
        hh, mm = map(int, s.split(':'))
        dt = now.replace(hour=hh, minute=mm, second=0, microsecond=0)
        if dt >= now + timedelta(minutes=10):
            return s, dt.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z')
    return None, None


def verify_caption(cap):
    banned = ['harga', 'biaya', 'murah', 'mahal', 'hemat', 'juta', 'rupiah']
    n_par = len([x for x in cap.split('\n\n') if x.strip()])
    checks = {
        '0 mention @': not re.search(r'@\w+', cap),
        'ada link dasindonesia (link == artikel)': ARTICLE_URL in cap,
        'ada ajakan diskusi': any(w in cap.lower() for w in ['komentar', 'diskusi', 'pendapat', 'menurut', 'share', 'setuju', 'pertimbangkan', 'pengalaman', 'cerita']),
        'tanpa kata harga/biaya': not any(w in cap.lower() for w in banned),
        'paragraf >= 2': n_par >= 2,
        'paragraf <= 4': n_par <= 4,
        'tidak ada hashtag huruf besar': not any(t != t.lower() for t in re.findall(r'#(\w+)', cap)),
        'tidak ada hashtag (pola Sep 2026)': not re.findall(r'#\w+', cap),
    }
    for k, v in checks.items():
        print(f"   [{'OK ' if v else 'X  '}] {k}")
    print(f"   (paragraf: {n_par}, panjang caption: {len(cap)} char)")
    return all(checks.values())


def main():
    history = load_history()
    pend, used, same_article = scan_account(TGL)
    print(f"  DAS FB pending {TGL}: {pend if pend else 'TIDAK ADA'}")

    if is_duplicate(history, ARTICLE_URL):
        print(f"X Artikel sudah pernah dipakai di history: {ARTICLE_URL}")
        sys.exit(1)
    if ARTICLE_URL.rstrip('/') in used:
        print(f"X Artikel sudah pernah dipakai di akun DAS FB (Repliz): {ARTICLE_URL}")
        sys.exit(1)
    if same_article:
        print(f"X Artikel ini SUDAH ada jadwal di akun DAS FB: {same_article} — batal (anti-dobel)")
        sys.exit(1)
    print(f"OK Artikel layak (0 hit history + 0 hit Repliz semua status, {len(used)} link terpakai): {ARTICLE_URL}")

    code = "000"
    for _ in range(4):
        code = subprocess.run(
            ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "120",
             "-A", "Mozilla/5.0", ARTICLE_URL + "/"],
            capture_output=True, text=True).stdout.strip()
        if code == "200":
            break
    print(f"   Artikel HTTP: {code}")
    if code != "200":
        print("X Artikel tidak live (bukan 200) — batal")
        sys.exit(1)

    if not verify_caption(CAPTION):
        print("X Caption gagal verifikasi — batal")
        sys.exit(1)

    if not os.path.exists(IMG_PATH):
        print(f"X Gambar tidak ada: {IMG_PATH}")
        sys.exit(1)

    jam, schedule_iso = pick_slot()
    if not jam:
        print("X Tidak ada slot tersisa hari ini — batal")
        sys.exit(1)
    print(f"   Slot dipilih: {TGL} {jam} WIB ({schedule_iso})")

    img_url = upload_image_to_server(IMG_PATH)
    print(f"   Image URL: {img_url}")
    if not img_url:
        print("X Upload image gagal — batal")
        sys.exit(1)

    # file hasil upload harus benar-benar ada & valid JPEG (penyebab error
    # 'Missing or invalid image file' yg berulang: media tidak terbaca Repliz)
    local_jpg = os.path.join(HERE, 'openclaw-img', os.path.basename(img_url))
    try:
        from PIL import Image
        im = Image.open(local_jpg)
        im.load()
        print(f"   File lokal: {local_jpg} — {im.size} {im.mode} {os.path.getsize(local_jpg)} bytes")
        if im.size != (1080, 1350):
            print("X Ukuran gambar bukan 1080x1350 — batal")
            sys.exit(1)
    except Exception as e:
        print(f"X File hasil upload tidak bisa dibuka sebagai image: {e} — batal")
        sys.exit(1)

    ok_ingress = False
    for ip in ("103.84.155.153", "103.84.155.217"):
        code = subprocess.run(
            ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "25",
             "--resolve", f"mantapserver.tail3947bb.ts.net:443:{ip}", img_url],
            capture_output=True, text=True).stdout
        print(f"   Ingress {ip}: HTTP {code}")
        if code == "200":
            ok_ingress = True
    code_local = subprocess.run(
        ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "15", img_url],
        capture_output=True, text=True).stdout
    print(f"   Local fetch: HTTP {code_local}")
    if not ok_ingress:
        print("X URL gambar tidak bisa diakses via ingress funnel — batal (Repliz ambil dari internet)")
        sys.exit(1)

    payload = {
        'title': '',
        'description': CAPTION,
        'topic': 'Otomotif',
        'type': 'image',
        'medias': [{'url': img_url, 'type': 'image'}],
        'meta': {'title': '', 'description': '', 'url': ''},
        'additionalInfo': {
            'isAiGenerated': False, 'isDraft': False,
            'collaborators': [], 'mentions': [],
            'music': {'id': '', 'artist': '', 'name': '', 'thumbnail': ''},
            'products': [], 'tags': []
        },
        'replies': [],          # FB tidak support replies (error postId)
        'accountId': FB_DAS_ID,
        'scheduleAt': schedule_iso,
    }

    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=60) as r:
            result = json.loads(r.read())
        sid = result.get('scheduleId') or result.get('_id') or result.get('id') or '?'
        print(f"OK SCHEDULED — Schedule ID: {sid}")

        time.sleep(4)
        ver, _, dup = scan_account(TGL)
        print(f"   Verifikasi pending DAS FB {TGL}: {ver}")
        if not ver:
            print("X Tidak ketemu jadwal pending di API — cek manual, jangan catat history dulu")
            sys.exit(1)
        if sid == '?':
            sid = ver[0][1]

        # verifikasi jadwal punya media + waktu yang benar
        chk = json.loads(urllib.request.urlopen(
            urllib.request.Request(f'{BASE}/public/schedule/{sid}', headers=HEADERS, method='GET'),
            timeout=60).read())
        print(f"   Jadwal: status={chk.get('status')} scheduleAt={chk.get('scheduleAt')} "
              f"type={chk.get('type')} medias={[m.get('url') for m in (chk.get('medias') or [])]} "
              f"replies={len(chk.get('replies') or [])}")
        assert chk.get('scheduleAt') == schedule_iso, "scheduleAt tidak sesuai!"
        assert chk.get('medias') and chk['medias'][0]['url'] == img_url, "media tidak sesuai!"
        assert not (chk.get('replies') or []), "replies harus kosong untuk FB!"

        history['posts'].append({
            'date': TGL,
            'time': jam,
            'platform': 'facebook',
            'article_url': ARTICLE_URL,
            'short_desc': CAPTION.split('\n\n')[0][:100],
            'schedule_id': sid,
            'image_source': 'openclaw-img',
        })
        with open(LOG_FILE, 'w') as f:
            json.dump(history, f, indent=2, ensure_ascii=False)
        print(f"   History dicatat: {LOG_FILE} (total posts: {len(history['posts'])})")
    except urllib.error.HTTPError as e:
        err = e.read().decode()
        print(f"X ERROR {e.code}: {err[:500]}")
        sys.exit(1)


if __name__ == '__main__':
    main()
