#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Tinjauan visual IG StudioSoft — FEED (carousel) dan REELS bergantian.

Perintah Bos 1 Okt 2026: "ini adalah tampilan feed n reels. jadi pastikan kamu
bisa cek bergantian seperti ini untuk reels n feednya".

Cara kerja:
  1. Ambil jadwal akun IG StudioSoft langsung dari Repliz (semua status).
  2. Kelompokkan per tanggal WIB. Untuk tiap tanggal:
       • album/feed  -> 10 slide gambar                (baris isi)
       • video/reel  -> potongan frame dari mp4-nya    (baris isi)
     Urutan baris = urutan jam tayang, jadi feed dan reels tampil bergantian.
  3. Susun contact sheet 5 kolom + label jam/tipe di tiap baris.

Contoh:
  python3 ss_ig_tinjau.py                       # hari ini (WIB), feed + reels
  python3 ss_ig_tinjau.py --tgl 2026-10-02
  python3 ss_ig_tinjau.py --hari 3              # hari ini + 2 hari berikutnya
  python3 ss_ig_tinjau.py --pakai story         # story ikut ditinjau
  python3 ss_ig_tinjau.py --pakai feed          # hanya feed
"""
from __future__ import annotations

import argparse
import datetime
import os
import subprocess
import sys
import tempfile

os.chdir("/home/mantapman/.hermes/profiles/atun/workspace")
sys.path.insert(0, os.getcwd())

from PIL import Image, ImageDraw, ImageFont  # noqa: E402
from repliz_client import get_client  # noqa: E402

ACC_IG_SS = "6a38ac33c5ff4ce3a3231232"
IMG_DIR = "openclaw-img"
WIB = datetime.timezone(datetime.timedelta(hours=7))
FONT_B = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
FONT_R = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
BG = (236, 238, 242)
BAR = (18, 43, 99)
NAVY = (18, 43, 99)
TW = 236            # lebar 1 tile
KOLOM = 5
PAD = 8
HEADER_H = 38
FRAME_PER_VIDEO = 4

URUT_TIPE = {"album": 0, "video": 1, "image": 2, "story": 3}
HARI_ID = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"]


def hari_indo(t: datetime.date) -> str:
    return HARI_ID[t.weekday()]


# ────────────────────────── data dari Repliz ──────────────────────────
def ambil_jadwal() -> list[dict]:
    c = get_client()
    keluar, page = [], 1
    while page <= 80:
        d = c.get_schedules(page=page, limit=50)
        items = d.get("docs") or d.get("data") or d.get("items") or []
        if not items:
            break
        for it in items:
            acc = it.get("accountId") or (it.get("account") or {}).get("_id")
            if acc == ACC_IG_SS:
                keluar.append(it)
        if len(items) < 50:
            break
        page += 1
    return keluar


def jam_wib(it: dict) -> datetime.datetime | None:
    at = it.get("scheduleAt") or ""
    try:
        return datetime.datetime.fromisoformat(at.replace("Z", "+00:00")).astimezone(WIB)
    except ValueError:
        return None


def nama_media(it: dict) -> list[tuple[str, str]]:
    """[(basename, url), ...]"""
    keluar = []
    for m in it.get("medias") or it.get("media") or []:
        if not isinstance(m, dict):
            continue
        url = m.get("url") or ""
        if url:
            keluar.append((url.split("/")[-1], url))
    return keluar


# ────────────────────────── media ──────────────────────────
def berkas_lokal(nama: str) -> str | None:
    p = os.path.join(IMG_DIR, nama)
    return p if os.path.exists(p) else None


def unduh(url: str, nama: str) -> str | None:
    p = os.path.join(tempfile.gettempdir(), "tinjau_" + nama)
    if os.path.exists(p):
        return p
    r = subprocess.run(["curl", "-s", "-L", "--max-time", "120", "-o", p, url],
                       capture_output=True)
    return p if r.returncode == 0 and os.path.exists(p) and os.path.getsize(p) > 1000 else None


def ambil_gambar(nama: str, url: str) -> Image.Image | None:
    p = berkas_lokal(nama) or unduh(url, nama)
    if not p:
        return None
    try:
        return Image.open(p).convert("RGB")
    except Exception:
        return None


def frame_video(nama: str, url: str, jumlah: int = FRAME_PER_VIDEO) -> list[Image.Image]:
    p = berkas_lokal(nama) or unduh(url, nama)
    if not p:
        return []
    try:
        dur = float(subprocess.run(
            ["ffprobe", "-v", "error", "-show_entries", "format=duration",
             "-of", "default=nw=1:nk=1", p],
            capture_output=True, text=True, timeout=60).stdout.strip() or 0)
    except Exception:
        dur = 0
    if dur <= 0:
        dur = 16.0
    tmpd = tempfile.mkdtemp(prefix="tinjau_")
    keluar = []
    for i in range(jumlah):
        t = dur * (i + 0.5) / jumlah
        out = os.path.join(tmpd, f"f{i}.jpg")
        subprocess.run(["ffmpeg", "-v", "error", "-ss", f"{t:.2f}", "-i", p,
                        "-frames:v", "1", "-q:v", "3", "-y", out], capture_output=True)
        if os.path.exists(out):
            keluar.append(Image.open(out).convert("RGB"))
    return keluar


# ────────────────────────── susun sheet ──────────────────────────
def baris_tile(baris: list[Image.Image], tw: int) -> tuple[Image.Image, int]:
    skala = [tw / im.width for im in baris]
    tinggi = int(max(im.height * s for im, s in zip(baris, skala)))
    lebar = len(baris) * tw + (len(baris) - 1) * PAD
    kanvas = Image.new("RGB", (lebar, tinggi), BG)
    x = 0
    for im, s in zip(baris, skala):
        kecil = im.resize((tw, int(im.height * s)), Image.LANCZOS)
        kanvas.paste(kecil, (x, (tinggi - kecil.height) // 2))
        x += tw + PAD
    return kanvas, tinggi


def buat_sheet(hari: list[tuple[datetime.date, list[dict]]], pakai: set[str],
               keluaran: str) -> str | None:
    f_label = ImageFont.truetype(FONT_B, 21)
    f_bar = ImageFont.truetype(FONT_R, 17)
    f_hari = ImageFont.truetype(FONT_B, 26)
    lebar_sheet = KOLOM * TW + (KOLOM - 1) * PAD + 2 * PAD
    bagian: list[tuple[str, object, str, str]] = []   # (jenis, isi, label, ket)

    for tgl, jadwal in hari:
        jadwal = [j for j in jadwal if j.get("type") in pakai]
        jadwal.sort(key=lambda j: (URUT_TIPE.get(j.get("type"), 9), jam_wib(j) or datetime.datetime.now(WIB)))
        if not jadwal:
            continue
        if len(hari) > 1:
            bagian.append(("hari", None,
                           f"{tgl:%d %b %Y} · {hari_indo(tgl)}", ""))
        for it in jadwal:
            jw = jam_wib(it)
            tipe = it.get("type")
            media = nama_media(it)
            ket = f"{len(media)} media · {(it.get('title') or '')[:34]}"
            if tipe in ("album", "image"):
                ims = [g for g in (ambil_gambar(n, u) for n, u in media) if g]
                for i in range(0, len(ims), KOLOM):
                    bagian.append((None, 0,
                                   f"FEED {jw:%H:%M} · {tipe} · slide {i+1}-{min(i+KOLOM, len(ims))}",
                                   ket if i == 0 else ""))
                    bagian.append(("ims", ims[i:i + KOLOM], "", ""))
            else:
                ims = frame_video(*media[0]) if media else []
                if ims:
                    bagian.append((None, 0,
                                   f"{'REEL' if tipe == 'video' else 'STORY'} {jw:%H:%M} · potongan frame",
                                   ket))
                    bagian.append(("ims", ims, "", ""))

    if not bagian:
        print("tidak ada media untuk ditinjau")
        return None

    # render langsung ke kanvas (tinggi dipangkas di akhir)
    kanvas = Image.new("RGB", (lebar_sheet, 6000), BG)
    d = ImageDraw.Draw(kanvas)
    y = PAD
    for jenis, isi, label, ket in bagian:
        if jenis == "hari":
            d.rectangle([PAD, y, lebar_sheet - PAD, y + HEADER_H + 6], fill=(255, 255, 255))
            d.text((PAD + 10, y + 8), label, font=f_hari, fill=NAVY)
            y += HEADER_H + 12
            continue
        if label:
            d.rectangle([PAD, y, lebar_sheet - PAD, y + HEADER_H], fill=BAR)
            d.text((PAD + 10, y + 9), label, font=f_label, fill=(255, 255, 255))
            if ket:
                d.text((PAD + 10 + d.textlength(label, font=f_label) + 16, y + 12),
                       ket, font=f_bar, fill=(190, 205, 235))
            y += HEADER_H + 4
            continue
        if jenis == "ims" and isi:
            gambar, h = baris_tile(isi, TW)
            kanvas.paste(gambar, (PAD, y))
            y += h + PAD
    kanvas = kanvas.crop((0, 0, lebar_sheet, min(y + PAD, kanvas.height)))
    kanvas.save(keluaran, quality=88)
    print(f"{keluaran} · {kanvas.size[0]}x{kanvas.size[1]} · "
          f"{len([b for b in bagian if b[0] == 'ims'])} baris")
    return keluaran


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--tgl", help="tanggal WIB YYYY-MM-DD (default: hari ini WIB)")
    ap.add_argument("--hari", type=int, default=1, help="tinjau N hari mulai --tgl")
    ap.add_argument("--pakai", nargs="*", default=["album", "video"],
                    choices=["album", "video", "image", "story"],
                    help="tipe jadwal yang ditinjau (default: feed + reels)")
    ap.add_argument("--out", default=None)
    ap.add_argument("--sisa", action="store_true",
                    help="hanya yang belum tayang: hari ini, jam tayang > sekarang (WIB)")
    a = ap.parse_args()

    sekarang = datetime.datetime.now(WIB)
    mulai = (datetime.date.fromisoformat(a.tgl) if a.tgl else sekarang.date())
    rentang = [mulai + datetime.timedelta(days=i) for i in range(a.hari)]

    jadwal = ambil_jadwal()
    per_hari: list[tuple[datetime.date, list[dict]]] = []
    for t in rentang:
        isi = [j for j in jadwal if (jw := jam_wib(j)) and jw.date() == t]
        if a.sisa:
            isi = [j for j in isi if jam_wib(j) > sekarang]
        isi.sort(key=lambda j: jam_wib(j))
        per_hari.append((t, isi))

    for t, isi in per_hari:
        jml = {tp: sum(1 for j in isi if j.get("type") == tp) for tp in ("album", "image", "video", "story")}
        print(f"{t} WIB — feed={jml['album'] + jml['image']} · reel={jml['video']} · story={jml['story']}")

    out = a.out or f"/tmp/ss_ig_tinjau_{mulai.isoformat()}{'' if a.hari == 1 else '_' + str(a.hari) + 'hari'}.jpg"
    buat_sheet(per_hari, set(a.pakai), out)


if __name__ == "__main__":
    main()
