#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""IG StudioSoft — setiap postingan FEED yang muncul juga ditayangkan di STORY.

Perintah Bos 30 Sep 2026: *"untuk IG StudioSoft semua postingan feed yang muncul, tampilkan juga
di Storynya"* → untuk tiap jadwal feed IG SS (reel/video, image, album) yang akan tayang, dibuatkan
satu jadwal `type=story` dengan media yang sama, 10 menit setelah jam tayang feed-nya.

Aturan yang dipakai:
  • Media sama (video reel → story video; image → story image; album → slide PERTAMA sebagai image).
  • Caption KOSONG (story IG memang tanpa caption), `replies=[]`.
  • Slot story 07:00/14:00/20:00 yang sudah jalan TIDAK diganggu — ini tambahan.
  • Idempoten: kalau sudah ada jadwal story IG SS di (scheduleAt feed + 10 menit) → SKIP.
  • Horizon sama dengan pipeline reel (default 4 hari); dijalankan di cron yang sama
    (`roll_ss_ig_reel.py`, 06:20 WIB) supaya selalu menyusul jadwal feed yang baru dibuat.

Pakai:
  python3 ss_ig_story_mirror.py --hari 4          # dry-run
  python3 ss_ig_story_mirror.py --hari 4 --go     # create
"""
import argparse
import datetime
import os
import re
import subprocess
import sys
import time

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
sys.path.insert(0, WS)
from repliz_client import get_client  # noqa: E402

IG_SS = "6a38ac33c5ff4ce3a3231232"
WIB = datetime.timezone(datetime.timedelta(hours=7))
GESER = datetime.timedelta(minutes=10)      # story tayang 10 menit setelah feed
# Perintah Bos 6 Okt 2026: "lakukan itu maksimal 1 story tiap hari".
# Hanya carousel/album feed (tayang 08:30) yang dicerminkan ke story, supaya story IG StudioSoft
# tetap satu per hari. Reel dan video tidak lagi dibuatkan story.
FEED = ("album",)
TOPIK = "IG StudioSoft Story Mirror"
IMG_DIR = os.path.join(WS, "openclaw-img")
IMG_BASE = "https://mantapserver.tail3947bb.ts.net"
INGRESS = ["103.84.155.153", "103.84.155.217"]
CANVAS_W, CANVAS_H = 1080, 1920


def cek_ingress(u):
    ok = True
    for ip in INGRESS:
        p = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--max-time", "30",
                            "--resolve", f"mantapserver.tail3947bb.ts.net:443:{ip}", u],
                           capture_output=True, text=True)
        kode = p.stdout.strip()
        print(f"      {ip}: {kode}")
        ok = ok and kode == "200"
    return ok


def kanvas_story(nama, paksa=False):
    """Slide 4:5 → media story 1080x1920 sewarna latar slide.

    Perintah Bos 1 Okt 2026 (screenshot story mirror carousel GEO yang kepotong kiri-kanan):
    IG memaksa media story memenuhi kanvas 9:16, jadi slide 4:5 apa adanya PASTI terpotong.
    Slide ditaruh utuh di tengah kanvas sewarna latarnya (piksel sudut), jadi tidak ada yang hilang.
    Return nama file baru (atau nama asli kalau gambarnya sudah 9:16).
    """
    src = os.path.join(IMG_DIR, nama)
    if not os.path.exists(src):
        return None
    baru = f"ss_story_canvas_{nama}"
    dst = os.path.join(IMG_DIR, baru)
    if os.path.exists(dst) and os.path.getsize(dst) > 1000 and not paksa:
        return baru
    from PIL import Image
    im = Image.open(src).convert("RGB")
    if im.size == (CANVAS_W, CANVAS_H):
        return nama
    bg = im.getpixel((8, 8))
    if min(bg) >= 235:
        bg = (255, 255, 255)
    skala = min(CANVAS_W / im.width, CANVAS_H / im.height)
    kecil = im.resize((round(im.width * skala), round(im.height * skala)), Image.LANCZOS)
    kanvas = Image.new("RGB", (CANVAS_W, CANVAS_H), bg)
    kanvas.paste(kecil, ((CANVAS_W - kecil.width) // 2, (CANVAS_H - kecil.height) // 2))
    kanvas.save(dst, quality=90)
    print(f"      kanvas story: {nama} → {baru} ({kanvas.size[0]}x{kanvas.size[1]}, bg {bg})")
    return baru


def semua_jadwal(c):
    docs, page = [], 1
    while page <= 200:
        r = None
        for a in range(6):
            try:
                r = c.get_schedules(page=page, limit=100)
                break
            except Exception:
                time.sleep(5 + 3 * a)
        if r is None:
            raise SystemExit("gagal membaca jadwal Repliz")
        b = r.get("docs") or []
        if not b:
            break
        docs += b
        if len(b) < 100:
            break
        page += 1
    return docs


def waktu(s):
    return datetime.datetime.fromisoformat(str(s).replace("Z", "+00:00"))


def media_story(d):
    """Media story: video apa adanya; image/album → slide pertama di kanvas 9:16 (biar tidak terpotong).

    Perintah Bos 20 Okt 2026: semua postingan IG StudioSoft pakai lagu → story gambar dijadikan
    video 8 dtk + bed musik (`ss_story_musik.video_story`). Kalau perakitan gagal, jatuh kembali
    ke story gambar supaya jadwal tetap jalan.
    """
    meds = d.get("medias") or []
    if not meds:
        return None
    m = meds[0]
    nama = (m.get("url") or "").split("/")[-1]
    if str(d.get("type")).lower() in ("video", "reel"):
        return {"url": m.get("url"), "type": "video", "alt": nama}
    baru = kanvas_story(nama)
    if not baru:
        return None
    import ss_story_musik as SM
    tgl = waktu(d.get("scheduleAt")).astimezone(WIB).date()
    vid = SM.video_story(baru, tgl)
    if vid:
        return {"url": f"{IMG_BASE}/openclaw-img/{vid}", "type": "video", "alt": vid}
    print("      ⚠️ video story gagal dirakit — pakai story gambar")
    return {"url": f"{IMG_BASE}/openclaw-img/{baru}", "type": "image", "alt": baru}


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--hari", type=int, default=4, help="horizon hari ke depan")
    ap.add_argument("--go", action="store_true")
    a = ap.parse_args()

    now = datetime.datetime.now(datetime.timezone.utc)
    batas = now + datetime.timedelta(days=a.hari)
    c = get_client()
    docs = semua_jadwal(c)

    feed, ada_story = [], set()
    for d in docs:
        if d.get("accountId") != IG_SS:
            continue
        w = waktu(d.get("scheduleAt"))
        if w.year >= 2099:
            continue
        if str(d.get("type")).lower() == "story":
            ada_story.add(d.get("scheduleAt"))
            continue
        if str(d.get("type")).lower() not in FEED:
            continue
        if str(d.get("status")).lower() not in ("pending", "process", "processing"):
            continue
        if not (now <= w <= batas):
            continue
        feed.append(d)

    feed.sort(key=lambda d: str(d.get("scheduleAt")))
    print(f"feed IG SS dalam horizon {a.hari} hari: {len(feed)} jadwal")

    rencana, gagal = [], 0
    for d in feed:
        at = (waktu(d.get("scheduleAt")) + GESER).strftime("%Y-%m-%dT%H:%M:%S.000Z")
        label = f"{waktu(d.get('scheduleAt')).astimezone(WIB):%d %b %H:%M} WIB"
        nama = ((d.get("medias") or [{}])[0].get("url") or "").split("/")[-1]
        if at in ada_story:
            print(f"  ⏭️  {label} ({d.get('type')}, {nama}) — story {at} sudah ada, SKIP")
            continue
        if waktu(at) <= now:
            print(f"  ⏭️  {label} — jam story sudah lewat, SKIP")
            continue
        med = media_story(d)
        if not med:
            print(f"  ❗ {label} — tanpa media, dilewati")
            gagal += 1
            continue
        rencana.append((at, label, d, med))

    for at, label, d, med in rencana:
        print(f"  {'+' if not a.go else '✅'} story {waktu(at).astimezone(WIB):%d %b %H:%M} WIB "
              f"← feed {label} ({d.get('type')}, {med['alt']})")
        if not a.go:
            continue
        if med["type"] in ("image", "video"):
            print("      cek media story:")
            if not cek_ingress(med["url"]):
                print("      ❗ media story tidak 200 di kedua ingress — lewati")
                gagal += 1
                continue
        sid = None
        for attempt in range(1, 4):
            try:
                res = c.create_schedule(IG_SS, "", at, title=f"Story IG SS mirror {med['alt']}",
                                        topic=TOPIK, type_="story", medias=[med], replies=[])
                sid = res.get("scheduleId") or res.get("_id") or res.get("id")
                break
            except Exception as e:
                print(f"      ⚠️ percobaan {attempt}: {str(e)[:110]}")
                time.sleep(8)
        if not sid:
            gagal += 1
            print("      ❌ create gagal")
            continue
        v = c.get_schedule(sid)
        v = v.get("data") or v
        if isinstance(v, dict) and "docs" in v:
            v = v["docs"][0]
        ok = v.get("status") == "pending" and v.get("type") == "story"
        gagal += 0 if ok else 1
        print(f"      {'✅' if ok else '⚠️'} id={sid} status={v.get('status')} "
              f"at={v.get('scheduleAt')} media={(v.get('medias') or [{}])[0].get('url', '').split('/')[-1]}")

    print(f"\nselesai: {len(rencana) - gagal} story mirror dibuat, {gagal} janggal")
    if a.go and not rencana:
        print("(semua postingan feed dalam horizon sudah punya story)")


if __name__ == "__main__":
    main()
