#!/usr/bin/env python3
"""
gen_uky_center.py — LAYOUT BAKU Threads @ukyhandoko (FIXED 16 Sep 2026, disetujui Bos).

SPESIFIKASI BAKU (jangan diubah tanpa perintah Bos):
  • Kanvas   : SQUARE 1080×1080 (bukan lagi 9:16 1080×1920)
  • Teks     : UKURAN SEMULA — judul Poppins-Bold 85, body Poppins-Regular 36
  • Isi teks : SATU BLOK DI TENGAH kanvas (jarak atas = jarak bawah, tidak ada
               void besar di bawah lagi) — perintah Bos: "designnya terlalu luas,
               jangan terlalu banyak space kosong dibawahnya"
  • Align    : RATA KIRI (perintah Bos 16 Sep 2026: "rata kiri aja")
  • Garis    : TANPA separator garis (perintah Bos: "hilangkan separator garis")
  • Header   : "@ukyhandoko" kiri-atas + nomor slide kanan-atas
  • Footer   : teks brand kiri-bawah ("@ukyhandoko • Founder StudioSoft" / dmark.id / studiosoft.id)

Cara pakai:
  preview : python3 gen_uky_center.py left preview square      → uky_preview/
  batch   : python3 gen_uky_center.py left batch square        → tulis ulang
            uky_threads_images/ (20 file) + uky3_output/ (17×3 file), backup .legacy-20260916

Sumber teks TIDAK diduplikasi: dibaca lewat AST dari skrip lama
  - generate_uky_threads_images.py  -> 20 slide uky_threads_images
  - gen_uky3.py LIST_POSTINGAN     -> quote card uky3_output
"""
import ast
import os
import sys
import shutil
from PIL import Image, ImageDraw, ImageFont

WS = os.path.expanduser("~/.hermes/profiles/atun/workspace")
if not os.path.isdir(WS):
    WS = os.path.expanduser("~/.openclaw/workspace-atun")

W, H = 1080, 1920
M = 70
MAX_W = W - 2 * M

BLUE = (18, 43, 99)          # #122B63 — BIRU TUA (perintah Bos 16 Sep 2026)
WHITE = (255, 255, 255)
ORANGE = (249, 115, 22)
BLUE_TEXT = (18, 43, 99)     # #122B63 — teks pada kartu background PUTIH (perintah Bos:
                             # "kalau yang bergantian, background putih + text #122B63")
NAME_COLOR = {"BLUE": BLUE, "WHITE": WHITE, "ORANGE": ORANGE, "BLUE_TEXT": BLUE_TEXT,
              "DARK": (40, 40, 40)}
# arsip: BLUE/BLUE_TEXT lama = (30, 64, 175) #1E40AF

FONT_DIR = os.path.expanduser("~/.fonts")
_cache = {}


def F(name, size):
    key = (name, size)
    if key not in _cache:
        _cache[key] = ImageFont.truetype(os.path.join(FONT_DIR, name), size)
    return _cache[key]


BOLD = lambda s: F("Poppins-Bold.ttf", s)
REG = lambda s: F("Poppins-Regular.ttf", s)


def wrap(text, font, max_w=MAX_W):
    lines, cur = [], ""
    for word in text.split():
        test = f"{cur} {word}" if cur else word
        if font.getbbox(test)[2] <= max_w:
            cur = test
        else:
            if cur:
                lines.append(cur)
            cur = word
    if cur:
        lines.append(cur)
    return lines


def title_fit(title, max_lines, start=85, max_w=MAX_W):
    """Cari ukuran font judul terbesar yang muat dalam max_lines baris."""
    ladder = [start] + [s for s in (110, 100, 96, 90, 85, 80, 75, 70, 66, 62, 58, 54, 50)
                        if s < start]
    for size in ladder:
        lines = wrap(title, BOLD(size), max_w)
        if len(lines) <= max_lines:
            return BOLD(size), lines
    return BOLD(50), wrap(title, BOLD(50), max_w)[:max_lines]


def render(bg, fg, title, body="", footer="", page="", filename=None,
           mode="center", out_dir=None, title_size=85, body_size=36,
           canvas=(W, H), divider=False, header="@ukyhandoko"):
    w, h = canvas
    MAXW = w - 2 * M
    img = Image.new("RGB", (w, h), bg)
    d = ImageDraw.Draw(img)

    f_head = REG(24)
    f_page = REG(20)
    f_foot = REG(20)
    f_title, t_lines = title_fit(title, 4, title_size, max_w=MAXW)
    t_step = f_title.size + 6
    f_body = REG(body_size)
    b_lines = wrap(body, f_body, MAXW) if body else []
    b_step = f_body.size + 12

    gap_title_div = int(f_title.size * 0.30) + 8   # kasih ruang descender (g, y, p)
    div_w = 170 if w >= 1000 else 150
    div_h = 3
    gap_div_body = 32
    # tanpa garis: satu jarak bersih judul → body
    gap_no_line = int(f_title.size * 0.45) + 16

    gap_mid = (gap_title_div + div_h + gap_div_body) if divider else gap_no_line
    block_h = len(t_lines) * t_step + gap_mid + len(b_lines) * b_step
    top_limit, bot_limit = 130, h - 110
    y0 = int((top_limit + bot_limit - block_h) / 2)
    y0 = max(top_limit, min(y0, bot_limit - block_h))

    def line_x(line, font):
        if mode == "center":
            return (w - font.getbbox(line)[2]) / 2
        return M

    y = y0
    for ln in t_lines:
        d.text((line_x(ln, f_title), y), ln, fill=fg, font=f_title)
        y += t_step

    if divider:
        y += gap_title_div
        if mode == "center":
            d.line([((w - div_w) / 2, y), ((w + div_w) / 2, y)], fill=fg, width=div_h)
        else:
            d.line([(M, y), (M + div_w, y)], fill=fg, width=div_h)
        y += div_h + gap_div_body
    else:
        y += gap_no_line

    for ln in b_lines:
        d.text((line_x(ln, f_body), y), ln, fill=fg, font=f_body)
        y += b_step

    # header + footer
    if mode == "center":
        d.text((w / 2, M - 26), header, font=f_head, fill=fg, anchor="ma")
        if page:
            d.text((w - M, M - 26), page, font=f_page, fill=fg, anchor="rt")
        if footer:
            d.text((w / 2, h - 44), footer, font=f_foot, fill=fg, anchor="ms")
    else:
        d.text((M, M - 26), header, font=f_head, fill=fg)
        if page:
            d.text((w - M, M - 26), page, font=f_page, fill=fg, anchor="rt")
        if footer:
            d.text((M, h - 44), footer, font=f_foot, fill=fg)

    if filename:
        out = os.path.join(out_dir or ".", filename)
        os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
        img.save(out, "PNG")
        return out
    return img


# ── SUMBER TEKS (dibaca dari generator lama, tanpa duplikasi) ─────────────
def load_uky_threads():
    path = os.path.join(WS, "generate_uky_threads_images.py")
    tree = ast.parse(open(path, encoding="utf-8").read())
    items = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Call) and getattr(node.func, "id", "") == "make_slide":
            kw = {}
            for k in node.keywords:
                try:
                    kw[k.arg] = ast.literal_eval(k.value)
                except Exception:
                    kw[k.arg] = getattr(k.value, "id", None)  # BLUE/WHITE/ORANGE
            if "filename" in kw and isinstance(kw.get("bg_color"), str):
                kw["bg_color"] = NAME_COLOR[kw["bg_color"]]
            if isinstance(kw.get("text_color"), str):
                kw["text_color"] = NAME_COLOR[kw["text_color"]]
            if "filename" in kw:
                items.append(kw)
    return items


def load_uky3():
    path = os.path.join(WS, "gen_uky3.py")
    tree = ast.parse(open(path, encoding="utf-8").read())
    for node in ast.walk(tree):
        if isinstance(node, ast.Assign) and getattr(node.targets[0], "id", "") == "LIST_POSTINGAN":
            return ast.literal_eval(node.value)
    return []


BG_MAP = {"BIRU": (BLUE, WHITE), "PUTIH": (WHITE, BLUE_TEXT), "ORANGE": (ORANGE, WHITE)}


def main():
    # DEFAULT = SPESIFIKASI BAKU (Bos 16 Sep 2026): rata kiri, square, teks semula, tanpa garis
    mode = sys.argv[1] if len(sys.argv) > 1 else "left"
    which = sys.argv[2] if len(sys.argv) > 2 else "preview"
    shape = sys.argv[3] if len(sys.argv) > 3 else "square"     # square | portrait
    big = (sys.argv[4] if len(sys.argv) > 4 else "") == "big"  # opsional: naik 1 tingkat

    if shape == "square":
        canvas = (1080, 1080)
        t_size, b_size = (100, 40) if big else (85, 36)
        tag = "SQ"
    else:
        canvas = (1080, 1920)
        t_size, b_size = (100, 40) if big else (85, 36)
        tag = "PT"

    out_dir = os.path.join(WS, "uky_preview" if which == "preview" else "")
    os.makedirs(out_dir, exist_ok=True)
    print(f"shape={shape} canvas={canvas} judul={t_size} body={b_size} mode={mode}")

    if which == "preview":
        # 2 slide contoh: yang Bos kirim (11) + item berikutnya di antrean (16)
        for src in load_uky_threads():
            fn = src["filename"]
            if not fn.startswith(("11_", "16_")):
                continue
            out = render(tuple(src["bg_color"]), tuple(src["text_color"]),
                         src["title"], src.get("body", ""), src.get("footer_text", ""),
                         src.get("page_number", ""),
                         filename=f"{tag}_{mode[0].upper()}_{fn}", mode=mode,
                         out_dir=out_dir, canvas=canvas,
                         title_size=t_size, body_size=b_size)
            print("✅", out, Image.open(out).size)
        return

    # batch: tulis ulang file sumber (backup .legacy-20260916 dulu)
    n = 0
    for src in load_uky_threads():
        p = os.path.join(WS, "uky_threads_images", src["filename"])
        if os.path.exists(p) and not os.path.exists(p + ".legacy-20260916"):
            shutil.copy2(p, p + ".legacy-20260916")
        render(tuple(src["bg_color"]), tuple(src["text_color"]), src["title"],
               src.get("body", ""), src.get("footer_text", ""),
               src.get("page_number", ""), filename=src["filename"], mode=mode,
               out_dir=os.path.join(WS, "uky_threads_images"),
               canvas=canvas, title_size=t_size, body_size=b_size)
        n += 1

    for k in load_uky3():
        for suf, (bg, fg) in BG_MAP.items():
            fn = f"{k['nama']}_{suf.lower()}.png"
            p = os.path.join(WS, "uky3_output", fn)
            if os.path.exists(p) and not os.path.exists(p + ".legacy-20260916"):
                shutil.copy2(p, p + ".legacy-20260916")
            render(bg, fg, k["judul"], k.get("body", ""), k.get("footer", ""),
                   "1/1", filename=fn, mode=mode,
                   out_dir=os.path.join(WS, "uky3_output"), canvas=canvas,
                   title_size=max(t_size, k.get("judul_size", t_size) + (15 if big else 0)),
                   body_size=k.get("body_size", b_size) + (4 if big else 0))
            n += 1
    print(f"✅ {n} file dirender ulang (mode={mode}, shape={shape})")


if __name__ == "__main__":
    main()
