#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Carousel 3 slide (padat) untuk feed Instagram The Skin Code Clinic.

Satu carousel = 3 slide:
  1. COVER  : foto wajah (Asia, pria/wanita sesuai tema) + judul + ringkasan isi
  2. ISI    : penjelasan padat (sebab, jenis, faktor)
  3. TINDAKAN: yang bisa dilakukan di rumah + di klinik, ditutup ajakan WhatsApp

Semua isi diambil dari artikel TSC sendiri (tsc_artikel_bekas_jerawat_cekung.py).
Output: tsc_car3/<nama>/slide_1..3.jpg
"""
import os
import sys

sys.path.insert(0, "/home/mantapman/.hermes/profiles/atun/workspace")
from PIL import Image, ImageChops, ImageDraw, ImageEnhance, ImageFilter, ImageOps
import tsc_feed_lib as L

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
OUT = f"{WS}/tsc_car3"

W, H, M = L.W, L.H, L.MARGIN
LEBAR = L.LEBAR
TERANG, BIRU = "#F7F8FA", "#DCE8F8"
NAVY, EMAS = L.NAVY, "#E9C64A"


def latar(corak):
    """Kembalikan (gambar, warna_judul, warna_tubuh, warna_kecil, putih)."""
    if corak == "gelap":
        im = L.gradasi("#2F3A4E", "#1B2436")
        L.lengkung(ImageDraw.Draw(im), geser=-140, warna="#3C4C68", tebal=3)
        return im, "#FFFFFF", "#D7E0EE", "#B9C6DA", True
    if corak == "biru":
        im = Image.new("RGB", (W, H), BIRU)
        L.lengkung(ImageDraw.Draw(im), warna="#FFFFFF", tebal=4)
        return im, NAVY, "#28407A", "#5A6B85", False
    im = Image.new("RGB", (W, H), TERANG)
    L.lengkung(ImageDraw.Draw(im))
    return im, NAVY, L.ABU_TUBUH, "#8A98AE", False


def crop_ke_rasio(foto, rasio, fokus=0.18):
    """Crop tengah foto ke rasio target TANPA mengubah proporsi (tidak di-stretch / tidak digepengkan).

    fokus = posisi potongan secara vertikal (0 = paling atas, 1 = paling bawah);
    dipakai supaya kepala/wajah tidak terpotong atas.
    """
    w, h = foto.size
    if w / h > rasio:                      # foto lebih lebar -> potong kiri-kanan
        lebar = max(1, int(round(h * rasio)))
        kiri = max(0, (w - lebar) // 2)
        return foto.crop((kiri, 0, kiri + lebar, h))
    tinggi = max(1, int(round(w / rasio)))  # foto lebih tinggi -> potong atas-bawah
    atas = max(0, min(int((h - tinggi) * fokus), h - tinggi))
    return foto.crop((0, atas, w, atas + tinggi))


def pasang_foto(im, path, corak, kotak, pusat, radius, jari=0.10, blur=110, natural=True):
    """Tempel foto wajah (crop, bukan digepengkan).

    natural=True -> warna asli foto dipertahankan (permintaan Bos 14 Okt 2026), hanya
    kontras dan kecerahan disesuaikan sedikit. natural=False -> duotone senada latar.
    """
    rx, ry = radius
    foto = crop_ke_rasio(Image.open(path).convert("RGB"), rx / ry)
    print(f"   foto {path.split('/')[-1]}: asli {Image.open(path).size} -> crop {foto.size} "
          f"(rasio {foto.size[0] / foto.size[1]:.3f} = target {rx / ry:.3f})"
          + ("  [warna natural]" if natural else "  [duotone]"))

    if natural:
        model = ImageEnhance.Contrast(foto).enhance(1.03)
        model = ImageEnhance.Brightness(model).enhance(1.01)
    else:
        abu = ImageOps.grayscale(foto)
        if corak == "gelap":
            model = ImageOps.colorize(abu, black=(24, 32, 46), white=(196, 210, 230))
        else:
            model = ImageOps.colorize(abu, black=(30, 45, 75), white=(250, 251, 253))
        model = ImageEnhance.Contrast(model).enhance(0.98)

    f = model.resize((int(rx * 2), int(ry * 2)), Image.LANCZOS)
    m = Image.new("L", f.size, 0)
    ImageDraw.Draw(m).ellipse([f.width * jari, f.height * jari * 0.7,
                               f.width * (1 - jari), f.height * (1 - jari * 0.7)], fill=255)
    m = m.filter(ImageFilter.GaussianBlur(blur))
    # fade kiri & atas: biar tepi foto tidak terlihat seperti kotak
    gx = Image.new("L", f.size, 0)
    gdx = ImageDraw.Draw(gx)
    for x in range(f.width):
        gdx.line([(x, 0), (x, f.height)], fill=int(255 * min(1.0, (x / max(f.width - 1, 1)) / 0.34)))
    gy = Image.new("L", f.size, 0)
    gdy = ImageDraw.Draw(gy)
    for yy in range(f.height):
        gdy.line([(0, yy), (f.width, yy)], fill=int(255 * min(1.0, (yy / max(f.height - 1, 1)) / 0.16)))
    grad = ImageChops.multiply(gx, gy).filter(ImageFilter.GaussianBlur(2))
    m = ImageChops.multiply(m, grad)
    im.paste(f, (int(pusat[0] - rx), int(pusat[1] - ry)), m)


# ─────────────── render blok teks (dengan auto-skalasi) ───────────────

def tata(d, data, s, hanya_ukur, warna_judul, warna_tubuh):
    y = data.get("y_awal", 296)
    f_judul = L.font("Playfair-Bold", max(42, int(data.get("ukuran_judul", 74) * max(s, 0.88))))
    while L.tinggi_teks(d, data["judul"], f_judul, LEBAR - 40, 6) > data.get("maks_judul", 200) and f_judul.size > 42:
        f_judul = L.font("Playfair-Bold", f_judul.size - 4)
    if not hanya_ukur:
        L.tulis(d, data["judul"], f_judul, M, y, LEBAR - 40, warna_judul, spasi=6)
    y += L.tinggi_teks(d, data["judul"], f_judul, LEBAR - 40, 6) + 20
    if not hanya_ukur:
        d.line([(M, y), (M + 120, y)], fill=EMAS if data.get("emas") else L.BIRU_MUDA, width=5)
    y += 36

    # jarak antar blok disamakan, dan ikut mengecil saat skala turun supaya tetap proporsional
    J_LEAD_BAWAH = int(22 * s)
    J_SUB_ATAS = int(28 * s)
    J_SUB_BAWAH = int(15 * s)
    J_TUBUH_BAWAH = int(18 * s)
    J_POIN_ANTAR = int(13 * s)
    J_CATATAN_ATAS = int(10 * s)
    J_CATATAN_BAWAH = int(16 * s)

    sebelumnya = "judul"
    for blok in data.get("blok", []):
        jenis = blok[0]
        if jenis == "sub" and sebelumnya != "judul":
            y += J_SUB_ATAS
        elif jenis == "catatan":
            y += J_CATATAN_ATAS
        if jenis == "lead":
            f = L.font("Poppins-SemiBold", max(23, int(32 * s)))
            if not hanya_ukur:
                L.tulis(d, blok[1], f, M, y, LEBAR, "#14264A" if not data.get("putih_teks") else "#FFFFFF", spasi=8)
            y += L.tinggi_teks(d, blok[1], f, LEBAR, 8) + J_LEAD_BAWAH
        elif jenis == "sub":
            f = L.font("Poppins-SemiBold", max(22, int(29 * s)))
            if not hanya_ukur:
                L.tulis(d, blok[1], f, M, y, LEBAR, warna_judul, spasi=7)
            y += L.tinggi_teks(d, blok[1], f, LEBAR, 7) + J_SUB_BAWAH
        elif jenis == "tubuh":
            f = L.font("Poppins-Regular", max(21, int(28 * s)))
            if not hanya_ukur:
                L.tulis(d, blok[1], f, M, y, LEBAR, warna_tubuh, spasi=10)
            y += L.tinggi_teks(d, blok[1], f, LEBAR, 10) + J_TUBUH_BAWAH
        elif jenis == "poin":
            f = L.font("Poppins-Regular", max(20, int(28 * s)))
            for i, p in enumerate(blok[1]):
                baris = L.lipat(d, p, f, LEBAR - 80)
                # tinggi teks nyata = jumlah baris * (font + jarak antar baris), tanpa jarak di baris terakhir
                tinggi_p = len(baris) * (f.size + 8) - 8
                if not hanya_ukur:
                    L.centang_bulat(d, M + 16, y + tinggi_p / 2 + 5, 13,
                                    warna=L.BIRU_AKSEN if not data.get("putih_teks") else "#9FB6DE")
                    L.tulis(d, p, f, M + 58, y, LEBAR - 80, warna_tubuh, spasi=8)
                y += len(baris) * (f.size + 8)
                if i < len(blok[1]) - 1:
                    y += J_POIN_ANTAR
        elif jenis == "catatan":
            f = L.font("Poppins-Regular", max(20, int(26 * s)))
            baris = L.lipat(d, blok[1], f, LEBAR - 76)
            tinggi = len(baris) * (f.size + 8) + 34
            if not hanya_ukur:
                d.rounded_rectangle([(M, y), (M + LEBAR, y + tinggi)], radius=16,
                                    fill="#1E2B40" if data.get("putih_teks") else "#E8F0FB")
                d.rounded_rectangle([(M, y), (M + 7, y + tinggi)], radius=4, fill=L.BIRU_AKSEN)
                L.tulis(d, blok[1], f, M + 34, y + 15, LEBAR - 76,
                        "#DCE6F5" if data.get("putih_teks") else "#24405F", spasi=8)
            y += tinggi + J_CATATAN_BAWAH
        sebelumnya = jenis
    return y


def cover(data, pakai_tag=True):
    """Cover carousel. `pakai_tag=False` dipakai untuk LinkedIn (satu gambar, tanpa ajakan geser)."""
    im, warna_judul, warna_tubuh, warna_kecil, putih = latar(data.get("corak", "gelap"))
    d = ImageDraw.Draw(im)
    d.im = im
    # foto wajah besar di kanan, melewati tepi bawah supaya terlihat sengaja
    pasang_foto(im, f"{WS}/{data['foto']}", data.get("corak", "gelap"),
                kotak=None, pusat=(data.get("foto_pusat", (800, 830))),
                radius=data.get("foto_radius", (430, 520)), jari=0.06, blur=120,
                natural=data.get("foto_natural", True))

    lg = L.logo(navy=not putih, lebar=200)
    im.paste(lg, (M, 74), lg)
    d.text((M, 74 + lg.height + 16), data["kicker"].upper(), font=L.font("Poppins-SemiBold", 23),
           fill="#C9D6E8" if putih else L.ABU_LEMBUT)

    f_judul = L.font("Playfair-Bold", data.get("ukuran_judul", 100))
    while L.tinggi_teks(d, data["judul"], f_judul, LEBAR - 180, 8) > 330 and f_judul.size > 54:
        f_judul = L.font("Playfair-Bold", f_judul.size - 4)
    y = L.tulis(d, data["judul"], f_judul, M, 350, LEBAR - 180, warna_judul, spasi=8)
    d.line([(M, y + 26), (M + 130, y + 26)], fill=EMAS, width=5)
    y += 76
    f_aksen = L.font("Playfair-BoldItalic", 54)
    y = L.tulis(d, data["aksen"], f_aksen, M, y, LEBAR - 180, EMAS, spasi=8) + 22

    f_isi = L.font("Poppins-Regular", 30)
    for b in data["ringkas"]:
        y = L.tulis(d, b, f_isi, M, y, LEBAR - 260, warna_tubuh, spasi=10)
        y += 12

    if pakai_tag:
        f_tag = L.font("Poppins-SemiBold", 28)
        tag = f"1/3  ·  GESER"
        tw = d.textlength(tag, font=f_tag)
        d.rounded_rectangle([(M, H - 250), (M + tw + 76, H - 176)], radius=37,
                            fill="#FFFFFF" if putih else NAVY)
        d.text((M + 38, H - 230), tag, font=f_tag, fill=NAVY if putih else "#FFFFFF")
    L._kaki(d, putih=putih)
    return im


def _pangkas_poin(data):
    """Buang satu poin terakhir dari blok poin terakhir yang isinya masih lebih dari satu.

    Dipakai kalau slide tetap meluber meski font sudah di skala terkecil.
    """
    for idx in range(len(data.get("blok", [])) - 1, -1, -1):
        blok = data["blok"][idx]
        if blok[0] == "poin" and len(blok[1]) > 1:
            data["blok"][idx] = ("poin", blok[1][:-1])
            return True
    return False


def isi(data, nomor):
    corak = data.get("corak_isi", "terang")
    im, warna_judul, warna_tubuh, warna_kecil, putih = latar(corak)
    d = ImageDraw.Draw(im)
    d.im = im
    L._kepala(d, putih=putih, counter=f"{nomor}/3", kicker=data["kicker"])
    # slide yang ber-CTA perlu ruang untuk tombol + napas di atas kaki
    batas = data.get("batas", (H - 330) if data.get("cta") else (H - 180))
    skala = (1.0, 0.96, 0.92, 0.88, 0.84, 0.80, 0.76, 0.72, 0.68, 0.64, 0.60)
    s = skala[-1]
    for _ in range(4):
        s = None
        for kandidat in skala:
            if tata(d, data, kandidat, True, warna_judul, warna_tubuh) <= batas:
                s = kandidat
                break
        if s is not None:
            break
        if not _pangkas_poin(data):
            s = skala[-1]
            break
    if s is None:
        s = skala[-1]
    y = tata(d, data, s, False, warna_judul, warna_tubuh)
    if y > batas:
        print(f"⚠️  {data['nama']} slide {nomor}: konten y={y:.0f} > batas {batas} (skala {s})")
    if data.get("cta"):
        L._pil_cta(d, M, min(max(y + 30, H - 360), H - 300), "Chat WhatsApp 0851-1744-4417",
                   lebar=690, tinggi=100, fill="#FFFFFF" if putih else NAVY,
                   teks_warna=NAVY if putih else "#FFFFFF")
    L._kaki(d, putih=putih)
    return im


if __name__ == "__main__":
    import importlib
    modul = sys.argv[1] if len(sys.argv) > 1 else "bekas_jerawat_cekung"
    mod = importlib.import_module(modul)
    for nama, data in mod.CAROUSEL.items():
        os.makedirs(f"{OUT}/{nama}", exist_ok=True)
        cover(data).save(f"{OUT}/{nama}/slide_1.jpg", quality=93)
        cover(data, pakai_tag=False).save(f"{OUT}/{nama}/slide_1_linkedin.jpg", quality=93)
        for i, blok in enumerate(data["slide"], 2):
            d2 = dict(blok)
            d2["nama"] = nama
            d2["kicker"] = blok.get("kicker", data["kicker"])
            d2["corak_isi"] = blok.get("corak_isi", "terang" if i == 2 else "biru")
            d2["putih_teks"] = d2["corak_isi"] == "gelap"
            isi(d2, i).save(f"{OUT}/{nama}/slide_{i}.jpg", quality=93)
        print("ok:", nama, "3 slide")
