#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""QC teks terpotong untuk desain feed The Skin Code.

Semua pemanggilan PIL `ImageDraw.text` dan penyimpanan gambar (`Image.save`) dipantau:
teks digambar lebih dulu, baru gambar disimpan — jadi setiap teks bisa dipetakan ke
berkas gambarnya. Lalu diperiksa:
  1. keluar kanvas atau masuk zona margin aman (tepi),
  2. bertumpuk dengan teks lain (irisan > 25% dari teks yang lebih kecil).

Jalankan: python3 tsc_cek_meluber.py
"""
import sys
from PIL import Image, ImageDraw

WS = "/home/mantapman/.hermes/profiles/atun/workspace"
sys.path.insert(0, WS)

CANVAS = (1080, 1350)
MARGIN_AMAN = 40
AMBANG_TUMPUK = 0.35   # huruf sambung (script) memang bertumpuk; tumpang tindih nyata antar elemen > 60%

_belum_dipetakan = []     # [(teks, bbox)] sejak gambar terakhir disimpan
_tombol_belum = []        # area tombol sejak gambar terakhir disimpan
GAMBAR = {}               # nama berkas -> [(teks, bbox)]
TOMBOL = {}               # nama berkas -> [(x0, y0, x1, y1)]


def pasang():
    asli_text = ImageDraw.ImageDraw.text
    asli_save = Image.Image.save

    def text_qc(self, xy, teks, *a, **kw):
        try:
            b = self.textbbox(xy, teks, font=kw.get("font"), stroke_width=kw.get("stroke_width", 0) or 0)
        except Exception:
            b = None
        if b and teks.strip():
            _belum_dipetakan.append((teks, b))
        return asli_text(self, xy, teks, *a, **kw)

    def save_qc(self, fp, *a, **kw):
        nama = str(fp)
        GAMBAR.setdefault(nama, []).extend(_belum_dipetakan)
        TOMBOL.setdefault(nama, []).extend(_tombol_belum)
        _belum_dipetakan.clear()
        _tombol_belum.clear()
        return asli_save(self, fp, *a, **kw)

    ImageDraw.ImageDraw.text = text_qc
    Image.Image.save = save_qc

    # catat area pil CTA supaya teks yang tertutup tombol ikut ketahuan
    try:
        import tsc_feed_lib as lib
        asli_pil = lib._pil_cta

        def pil_qc(draw, x, y, teks, lebar=580, tinggi=98, fill=None, teks_warna=None):
            _tombol_belum.append((x, y, x + lebar, y + tinggi))
            return asli_pil(draw, x, y, teks, lebar=lebar, tinggi=tinggi, fill=fill, teks_warna=teks_warna)

        lib._pil_cta = pil_qc
    except Exception:
        pass
    return asli_text, asli_save


def _gabung_baris(item):
    """Gabungkan bbox per karakter menjadi satu bbox per baris.

    Pada `teks_track` teks digambar huruf demi huruf ke kanan, lalu panggilan berikutnya
    dimulai lagi dari kiri. Jadi baris baru dideteksi dari posisi x yang mundur —
    jauh lebih andal daripada menebak lewat kedekatan bbox (yang bisa menyembunyikan
    tumpang tindih sungguhan antar baris).
    """
    baris = []
    for teks, b in item:
        lanjut = False
        if baris:
            gb = baris[-1][1]
            # masih satu baris kalau huruf ini masih berada di rentang vertikal baris
            # berjalan DAN posisinya belum mundur jauh dari ujung kanan (kerning/bearing
            # huruf sambung boleh mundur sedikit)
            if b[1] < gb[3] and b[0] >= gb[2] - 20:
                lanjut = True
        if lanjut:
            g = baris[-1]
            g[0] += teks
            g[1] = [min(g[1][0], b[0]), min(g[1][1], b[1]), max(g[1][2], b[2]), max(g[1][3], b[3])]
        else:
            baris.append([teks, list(b)])
    return [(t, tuple(b)) for t, b in baris]


def periksa(nama):
    masalah = []
    item = GAMBAR.get(nama, [])
    if not item:
        return [f"  ⚠️  tidak ada teks tercatat untuk {nama} — QC tidak sah"]
    baris = _gabung_baris(item)

    for teks, b in baris:
        if b[0] < MARGIN_AMAN or b[1] < MARGIN_AMAN or b[2] > CANVAS[0] - MARGIN_AMAN or b[3] > CANVAS[1] - MARGIN_AMAN:
            masalah.append(f"  tepi: «{teks[:48]}» bbox={b}")
    for i in range(len(baris)):
        for j in range(i + 1, len(baris)):
            (t1, b1), (t2, b2) = baris[i], baris[j]
            ix = min(b1[2], b2[2]) - max(b1[0], b2[0])
            iy = min(b1[3], b2[3]) - max(b1[1], b2[1])
            if ix <= 0 or iy <= 0:
                continue
            kecil = min((b1[2] - b1[0]) * (b1[3] - b1[1]), (b2[2] - b2[0]) * (b2[3] - b2[1]))
            if kecil and (ix * iy) / kecil > AMBANG_TUMPUK:
                masalah.append(f"  tumpuk: «{t1[:26]}» vs «{t2[:26]}» irisan={ix * iy / kecil:.0%}")
    # teks yang tertutup tombol/pil CTA (teks di dalam tombol itu sendiri dikecualikan)
    for teks, b in baris:
        luas = max(1, (b[2] - b[0]) * (b[3] - b[1]))
        for (x0, y0, x1, y1) in TOMBOL.get(nama, []):
            ix = min(b[2], x1) - max(b[0], x0)
            iy = min(b[3], y1) - max(b[1], y0)
            if ix > 0 and iy > 0 and (ix * iy) / luas < 0.92:
                masalah.append(f"  nabrak tombol: «{teks[:40]}» bbox={b} vs tombol={(x0, y0, x1, y1)}")
                break
    return masalah


if __name__ == "__main__":
    import importlib

    asli_text, asli_save = pasang()
    total = 0
    try:
        import tsc_feed_bjc_render  # noqa: F401  (render 10 slide)
        import runpy
        # kartu foto dijalankan sebagai __main__ supaya blok render-nya ikut jalan
        runpy.run_path(f"{WS}/tsc_ads_sample/buat_feed_foto.py", run_name="__main__")
    finally:
        ImageDraw.ImageDraw.text = asli_text
        Image.Image.save = asli_save

    print("berkas diperiksa:", len(GAMBAR))
    for nama in sorted(GAMBAR):
        m = periksa(nama)
        total += len(m)
        pendek = nama.replace(WS + "/", "").replace("/tmp/tsc_feed_bjc/", "")
        print(f"{pendek}: {len(GAMBAR[nama])} teks → {'OK' if not m else str(len(m)) + ' temuan'}")
        for baris in m:
            print(baris)
    print(f"\nTOTAL TEMUAN: {total}")
