#!/usr/bin/env catnip
# Manipulation d'images avec Pillow (PIL)
# Pillow : lecture, transformations, filtres, conversion de formats
#
# DEPS: pillow

# PIL est un namespace package (pas de __init__.py qui importe ses sous-modules),
# ce qui empêche l'écriture : import('PIL', 'Image', )
Image = import('PIL.Image')
ImageFilter = import('PIL.ImageFilter')
ImageDraw = import('PIL.ImageDraw')
ImageStat = import('PIL.ImageStat')
import('pathlib', 'Path')

# Résolution relative au script (fonctionne depuis n'importe quel CWD)
script_dir = Path(META.file).parent
output_dir = script_dir / "output"
output_dir.mkdir(exist_ok=True)

# Struct Transform : pipeline déclaratif
struct Transform {
    name; apply

    run(self, img) => {
        result = self.apply(img)
        result.save(output_dir / f"catnip_{self.name}.jpg")
        print(f"  {self.name} → catnip_{self.name}.jpg")
        result
    }
}

# Chargement
print("⇒ Chargement d'image")
img = Image.open(script_dir / "data/catnip_test.jpg")
print(f"  format: {img.format}, size: {img.size}, mode: {img.mode}")

# Transformations géométriques via broadcasting
print()
print("⇒ Transformations géométriques")

geo_transforms = list(
    Transform("resized", (i) => { i.resize(tuple(200, 150)) }),
    Transform("rotated", (i) => { i.rotate(45) }),
    Transform("flip_h", (i) => { i.transpose(Image.FLIP_LEFT_RIGHT) }),
    Transform("flip_v", (i) => { i.transpose(Image.FLIP_TOP_BOTTOM) }),
)

geo_transforms.[(t) => { t.run(img) }]

# Thumbnail (modifie in-place, cas à part)
thumb = img.copy()
thumb.thumbnail(tuple(100, 100))
thumb.save(str(output_dir / "catnip_thumb.jpg"))
print(f"  thumb → catnip_thumb.jpg")

# Crop (calcul dynamique, cas à part)
left = (img.width - 200) / 2
top = (img.height - 200) / 2
cropped = img.crop(tuple(left, top, left + 200, top + 200))
cropped.save(str(output_dir / "catnip_cropped.jpg"))
print(f"  cropped → catnip_cropped.jpg")

# Filtres via broadcasting
print()
print("⇒ Filtres et effets")

filter_transforms = list(
    Transform("blur", (i) => { i.filter(ImageFilter.BLUR) }),
    Transform("sharpen", (i) => { i.filter(ImageFilter.SHARPEN) }),
    Transform("contour", (i) => { i.filter(ImageFilter.CONTOUR) }),
    Transform("edges", (i) => { i.filter(ImageFilter.EDGE_ENHANCE) }),
)

filter_transforms.[(t) => { t.run(img) }]

# Conversions
print()
print("⇒ Conversions")

gray = img.convert("L")
gray.save(str(output_dir / "catnip_gray.jpg"))
print(f"  grayscale → catnip_gray.jpg")

rgba = img.convert("RGBA")
rgba.save(str(output_dir / "catnip_rgba.png"))
print(f"  RGBA PNG → catnip_rgba.png")

img.save(str(output_dir / "catnip_converted.png"))
print(f"  format PNG → catnip_converted.png")

# Manipulation de pixels
print()
print("⇒ Manipulation de pixels")

canvas = Image.new("RGB", tuple(100, 100), tuple(255, 255, 255))

for x in range(100) {
    for y in range(100) {
        r = int((x * 255) / 100)
        b = int((y * 255) / 100)
        canvas.putpixel(tuple(x, y), tuple(r, 0, b))
    }
}

canvas.save(str(output_dir / "catnip_gradient.png"))
print(f"  gradient → catnip_gradient.png")

# Ajout de texte et formes
print()
print("⇒ Ajout de texte")

text_img = img.copy()
draw = ImageDraw.Draw(text_img)
draw.text(tuple(10, 10), "Catnip + Pillow", tuple(255, 255, 255))
draw.rectangle(list(tuple(50, 50), tuple(150, 100)), "red", "yellow")
draw.ellipse(list(tuple(200, 50), tuple(300, 150)), "blue", "cyan")

text_img.save(str(output_dir / "catnip_annotated.jpg"))
print(f"  annotated → catnip_annotated.jpg")

# Batch processing via broadcasting
print()
print("⇒ Traitement par lot")

batch_sizes = list(tuple(100, 100), tuple(200, 150), tuple(300, 200))

for size in batch_sizes {
    t = img.copy()
    t.thumbnail(size)
    filename = f"catnip_batch_{size}.jpg"
    t.save(str(output_dir / filename))
    print(f"  {size} → {filename}")
}

# Analyse d'image
print()
print("⇒ Analyse d'image")

stats = ImageStat.Stat(img)
print(f"  Moyenne par canal (RGB) : {stats.mean}")
print(f"  Médiane par canal (RGB) : {stats.median}")
print(f"  Écart-type par canal (RGB) : {stats.stddev}")
print(f"  Min/max par canal (RGB) : {stats.extrema}")

# Résumé
print()
print("⇒ Résumé")
print(f"Images générées dans {output_dir} :")

categories = list(
    "  - Transformations : resized, rotated, cropped, flipped",
    "  - Filtres : blur, sharpen, contour, edges",
    "  - Conversions : grayscale, RGBA, PNG",
    "  - Effets : gradient, annotations",
    "  - Batch : thumbnails multiples",
)
for cat in categories { print(cat) }