"""watermark: marca de agua de texto con Pillow (sin GPU ni red).

    # CLI sobre un fichero o un directorio (recursivo), marca de agua:
    python Engine/watermark.py --in Output/pilots --out "$env:TEMP\\wm_out" \
        --text "PlumLoom" --position bottom-right --opacity 0.35

    # --text "" (o sin --text) = copia plana, byte a byte (no carga fuente).

La parte de watermarking la usa el paso de packaging de pack_builder.py
(--pack): con --watermark "<texto>" marca, sin el copia en plano.

Diseño:
- `apply_watermark` lee la imagen, la compone con un overlay RGBA (el canal
  alfa del texto = `opacity`, así se respeta la transparencia) y la guarda en
  `dst`. Nunca escribe si `src` y `dst` son el mismo fichero.
- `watermark_dir` recorre `in_dir` con `rglob("*.png")` (recursivo) y preserva
  la ruta relativa bajo `out_dir`; en un dir plano el nombre coincide.
"""
import argparse
import shutil
import sys
from pathlib import Path

sys.stdout.reconfigure(encoding="utf-8", errors="backslashreplace")

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

BASE_DIR = Path(__file__).resolve().parent.parent

POSITIONS = ("bottom-right", "bottom-left", "top-right", "top-left", "center")

FONT_PATH = Path(r"C:\Windows\Fonts\arial.ttf")

# Margen de la marca respecto al borde, como fracción del lado menor.
_PAD_FRAC = 0.02


def _load_font(size):
    """arial.ttf si está; si no, la fuente por defecto (tamaño ignorado)."""
    try:
        return ImageFont.truetype(str(FONT_PATH), size)
    except Exception:
        try:
            return ImageFont.load_default(size)
        except TypeError:
            return ImageFont.load_default()


def _text_xy(w, h, tw, th, pad, position):
    """Esquina superior-izquierda (X, Y) del bloque de texto, según posición."""
    if position == "bottom-right":
        return w - pad - tw, h - pad - th
    if position == "bottom-left":
        return pad, h - pad - th
    if position == "top-right":
        return w - pad - tw, pad
    if position == "top-left":
        return pad, pad
    return (w - tw) / 2, (h - th) / 2  # center


def apply_watermark(src, dst, text, position="bottom-right",
                    opacity=0.35, scale=0.035):
    """Escribe `src` en `dst` con la marca `text`.

    `scale` = tamaño de fuente como fracción del ancho. `opacity` (0..1) va en
    el canal alfa del texto. `text=""` copia el fichero tal cual (nunca falla
    por fuente). Crea los directorios padre de `dst`. Si `src == dst` (mismo
    fichero) NO escribe nada: lanza ValueError para no truncar el original.
    """
    src = Path(src)
    dst = Path(dst)
    if position not in POSITIONS:
        raise ValueError(f"posicion invalida: {position!r}; usa {POSITIONS}")
    if src.resolve() == dst.resolve():
        raise ValueError(f"src y dst son el mismo fichero: {src}")

    dst.parent.mkdir(parents=True, exist_ok=True)

    if not text:
        shutil.copyfile(src, dst)
        return

    alpha = max(0, min(255, round(float(opacity) * 255)))
    with Image.open(src) as opened:
        base = opened.convert("RGBA")
    w, h = base.size
    font = _load_font(max(1, round(float(scale) * w)))
    overlay = Image.new("RGBA", (w, h), (0, 0, 0, 0))
    draw = ImageDraw.Draw(overlay)
    bbox = draw.textbbox((0, 0), text, font=font)
    tw = bbox[2] - bbox[0]
    th = bbox[3] - bbox[1]
    pad = max(1, round(min(w, h) * _PAD_FRAC))
    x, y = _text_xy(w, h, tw, th, pad, position)
    # compensa el offset del bbox para que la tinta caiga en (x, y)
    draw.text((x - bbox[0], y - bbox[1]), text, font=font,
              fill=(255, 255, 255, alpha))
    composed = Image.alpha_composite(base, overlay).convert("RGB")
    composed.save(dst)


def watermark_dir(in_dir, out_dir, text, **kw):
    """Marca cada `*.png` de `in_dir` (recursivo) en `out_dir/<ruta relativa>`.

    -> lista de ficheros escritos (orden por ruta de origen).
    """
    in_dir = Path(in_dir)
    out_dir = Path(out_dir)
    written = []
    for src in sorted(in_dir.rglob("*.png")):
        dst = out_dir / src.relative_to(in_dir)
        apply_watermark(src, dst, text, **kw)
        written.append(dst)
    return written


def main():
    p = argparse.ArgumentParser(description="Marca de agua de texto (Pillow)")
    p.add_argument("--in", dest="inp", required=True,
                   help="directorio (recursivo) o PNG de entrada")
    p.add_argument("--out", dest="out", required=True,
                   help="directorio de salida")
    p.add_argument("--text", default="",
                   help="texto de la marca; vacio = copia plana")
    p.add_argument("--position", default="bottom-right", choices=POSITIONS)
    p.add_argument("--opacity", type=float, default=0.35)
    p.add_argument("--scale", type=float, default=0.035)
    args = p.parse_args()

    src = Path(args.inp)
    out = Path(args.out)
    kw = {"position": args.position, "opacity": args.opacity,
          "scale": args.scale}
    if src.is_dir():
        written = watermark_dir(src, out, args.text, **kw)
    elif src.is_file():
        dst = out / src.name
        apply_watermark(src, dst, args.text, **kw)
        written = [dst]
    else:
        raise SystemExit(f"[!] no existe: {src}")

    print(f"[OK] {len(written)} ficheros -> {out}")


if __name__ == "__main__":
    main()
