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

Cron fb-das-harian jalan 17:00 WIB (10:00 UTC) → slot 17:00 WIB sudah LEWAT saat script
jalan (preseden schedule_das_fb_20260901..11.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).

Artikel: https://dasindonesia.com/bengkel-buka-hari-minggu-surabaya
- Publish hari ini 2026-09-12 03:33 (masih sangat baru), belum pernah dipakai.
- Dicek dengan scan_das_unused2.py (diff 209 artikel live vs link terpakai di post_das_fb_history.json
  + SELURUH jadwal akun DAS FB semua status) → 0 hit. Prompt menawarkan
  penyebab-mesin-mobil-overheat & kapan-mobil-perlu-engine-overhaul, tapi KEDUANYA SUDAH terpakai.

Format: image 1080x1350 (bg #1a1a2e, teks putih, aksen #f97316) + caption 3 paragraf + link +
pancingan diskusi netral (diskusi_engine otomotif).
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

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_20260912.png')
ARTICLE_URL = "https://dasindonesia.com/bengkel-buka-hari-minggu-surabaya"
TGL = "2026-09-12"

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

CAPTION = """Akhir pekan sering jadi satu-satunya waktu luang untuk mengurus mobil. Masalahnya, tidak semua bengkel melayani Sabtu-Minggu — dan yang buka pun biasanya hanya sanggup mengerjakan perawatan ringan.

Kabar baiknya, sebagian besar pekerjaan rutin justru bisa selesai dalam sehari: servis berkala, pemeriksaan kaki-kaki, servis rem, perawatan AC, sampai rotasi dan penyeimbangan ban. Yang perlu dijaga hanya dua hal — booking lebih dulu karena slot akhir pekan cepat penuh, dan datang lebih pagi sebelum antrean siang menumpuk.

Kalau Anda berencana memanfaatkan akhir pekan ini untuk servis, kami sudah rangkum pekerjaan yang cocok dikerjakan hari Minggu, hal yang sebaiknya Anda periksa sendiri sebelum berangkat, sampai jadwal operasional yang perlu dikonfirmasi lebih dulu di artikel ini:
""" + ARTICLE_URL + """

Pernah mengalami mesin bermasalah di tengah perjalanan? Ceritakan pengalamanmu di kolom komentar!"""


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."""
    pend, used = [], 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
            for l in re.findall(r'https?://dasindonesia\.com[^\s]*', (d.get('description') or '')):
                used.add(l.rstrip('/'))
            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


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']),
        '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)),
    }
    for k, v in checks.items():
        print(f"   [{'✅' if v else '❌'}] {k}")
    print(f"   (paragraf: {n_par}, panjang caption: {len(cap)} char)")
    return all(checks.values())


def main():
    history = load_history()
    pend, used = scan_account(TGL)
    print(f"  DAS FB pending {TGL}: {pend if pend else 'TIDAK ADA'}")
    if pend:
        print("❌ Sudah ada jadwal DAS FB hari ini — batal, jangan double-book")
        sys.exit(1)

    if is_duplicate(history, ARTICLE_URL):
        print(f"❌ Artikel sudah pernah dipakai di history: {ARTICLE_URL}")
        sys.exit(1)
    if ARTICLE_URL.rstrip('/') in used:
        print(f"❌ Artikel sudah pernah dipakai di akun DAS FB (Repliz): {ARTICLE_URL}")
        sys.exit(1)
    print(f"✅ Artikel layak (0 hit history + 0 hit Repliz semua status, {len(used)} link terpakai): {ARTICLE_URL}")

    code = "000"
    for _ in range(3):
        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("❌ Artikel tidak live (bukan 200) — batal")
        sys.exit(1)

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

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

    jam, schedule_iso = pick_slot()
    if not jam:
        print("❌ 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("❌ 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")
    except Exception as e:
        print(f"❌ 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("❌ 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"✅ SCHEDULED — Schedule ID: {sid}")

        time.sleep(4)
        ver, _ = scan_account(TGL)
        print(f"   Verifikasi pending DAS FB {TGL}: {ver}")
        if not ver:
            print("❌ Tidak ketemu jadwal pending di API — cek manual, jangan catat history dulu")
            sys.exit(1)
        if len(ver) > 1:
            print(f"⚠️  Ada {len(ver)} pending hari ini — cek duplikat!")
        if sid == '?':
            sid = ver[0][1]

        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"❌ ERROR {e.code}: {err[:500]}")
        sys.exit(1)


if __name__ == '__main__':
    main()
