#!/usr/bin/env python3
"""Génère la variante putaclic skimmer + slides carrousel (les autres posts = image à la une WP)."""

from __future__ import annotations

import math
import textwrap
from pathlib import Path

from PIL import Image, ImageChops, ImageDraw, ImageEnhance, ImageFilter, ImageFont, ImageOps

ROOT = Path(__file__).resolve().parents[1]
OUT_DIR = ROOT / "www/propositions/planning-social-ete-2026/visuels"
PHOTO_PATH = ROOT / "assets/arnaud-headshot-square.png"

SIZE = 1200
ORANGE = (233, 128, 48)
RED = (210, 35, 35)
DARK_RED = (28, 8, 8)
BLACK = (17, 17, 17)
WHITE = (255, 255, 255)


def load_font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
    candidates = [
        "/System/Library/Fonts/Supplemental/Arial Bold.ttf" if bold else "/System/Library/Fonts/Supplemental/Arial.ttf",
        "/Library/Fonts/Arial Bold.ttf" if bold else "/Library/Fonts/Arial.ttf",
    ]
    for path in candidates:
        if Path(path).exists():
            return ImageFont.truetype(path, size)
    return ImageFont.load_default()


def draw_text_stroke(
    draw: ImageDraw.ImageDraw,
    xy: tuple[float, float],
    text: str,
    font: ImageFont.ImageFont,
    fill: tuple[int, int, int],
    stroke: tuple[int, int, int],
    stroke_width: int = 4,
    anchor: str = "mm",
) -> None:
    draw.text(xy, text, fill=stroke, font=font, anchor=anchor, stroke_width=stroke_width + 2, stroke_fill=stroke)
    draw.text(xy, text, fill=fill, font=font, anchor=anchor)


def radial_glow(size: tuple[int, int], center: tuple[int, int], radius: int, color: tuple[int, int, int]) -> Image.Image:
    glow = Image.new("RGBA", size, (0, 0, 0, 0))
    draw = ImageDraw.Draw(glow)
    for r in range(radius, 0, -4):
        alpha = int(120 * (1 - r / radius) ** 1.8)
        draw.ellipse(
            (center[0] - r, center[1] - r, center[0] + r, center[1] + r),
            fill=(*color, alpha),
        )
    return glow.filter(ImageFilter.GaussianBlur(18))


def prepare_portrait(photo: Image.Image) -> tuple[Image.Image, Image.Image]:
    """Recadre, dramatise et colore le portrait (effet choc / étonnement)."""
    w, h = photo.size
    crop = photo.crop((int(w * 0.05), 0, w, h))
    crop = ImageOps.fit(crop, (680, 980), method=Image.Resampling.LANCZOS, centering=(0.5, 0.28))

    crop = ImageEnhance.Contrast(crop).enhance(1.2)
    crop = ImageEnhance.Color(crop).enhance(1.12)
    crop = ImageEnhance.Brightness(crop).enhance(1.18)
    crop = ImageEnhance.Sharpness(crop).enhance(1.15)

    # Teinte chaude légère
    tint = Image.new("RGB", crop.size, (180, 60, 30))
    crop = Image.blend(crop, tint, 0.08)

    # Masque : fondu gauche + bas pour intégration
    mask = Image.new("L", crop.size, 255)
    mdraw = ImageDraw.Draw(mask)
    mdraw.rectangle((0, 0, 100, crop.size[1]), fill=0)
    mdraw.rectangle((0, crop.size[1] - 30, crop.size[0], crop.size[1]), fill=0)
    mask = mask.filter(ImageFilter.GaussianBlur(30))
    return crop, mask


def draw_shock_burst(draw: ImageDraw.ImageDraw, cx: int, cy: int, radius: int = 90) -> None:
    """Éclat graphique « choc » derrière la tête."""
    points = []
    spikes = 14
    for i in range(spikes * 2):
        angle = math.pi * i / spikes - math.pi / 2
        r = radius if i % 2 == 0 else radius * 0.45
        points.append((cx + math.cos(angle) * r, cy + math.sin(angle) * r))
    draw.polygon(points, fill=(255, 220, 60))
    draw.ellipse((cx - 28, cy - 28, cx + 28, cy + 28), fill=RED)
    draw.text((cx, cy), "!", fill=WHITE, font=load_font(52, True), anchor="mm")


def render_skimmer_clickbait() -> Image.Image:
    canvas = Image.new("RGB", (SIZE, SIZE), DARK_RED)
    draw = ImageDraw.Draw(canvas)

    # Fond dégradé dramatique (plus lumineux)
    for y in range(SIZE):
        t = y / SIZE
        color = (int(55 - 20 * t), int(14 - 6 * t), int(12 - 5 * t))
        draw.line([(0, y), (SIZE, y)], fill=color)

    # Lignes « scan » discrètes
    overlay = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
    odraw = ImageDraw.Draw(overlay)
    for y in range(0, SIZE, 6):
        odraw.line([(0, y), (SIZE, y)], fill=(255, 255, 255, 8))
    canvas = Image.alpha_composite(canvas.convert("RGBA"), overlay).convert("RGB")
    draw = ImageDraw.Draw(canvas)

    # Bandeau alerte
    draw.rectangle((0, 0, SIZE, 110), fill=RED)
    draw_text_stroke(
        draw, (SIZE // 2, 55), "ALERTE SÉCURITÉ PRESTASHOP",
        load_font(40, True), WHITE, (120, 10, 10), stroke_width=3,
    )

    # Portrait
    if not PHOTO_PATH.exists():
        raise FileNotFoundError(f"Photo introuvable : {PHOTO_PATH}")
    portrait, portrait_mask = prepare_portrait(Image.open(PHOTO_PATH).convert("RGB"))

    # Glow derrière le visage
    glow = radial_glow((SIZE, SIZE), (900, 480), 280, ORANGE)
    canvas = Image.alpha_composite(canvas.convert("RGBA"), glow).convert("RGB")

    # Éclat choc
    shock_layer = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
    sdraw = ImageDraw.Draw(shock_layer)
    draw_shock_burst(sdraw, 1040, 250, 95)
    canvas = Image.alpha_composite(canvas.convert("RGBA"), shock_layer).convert("RGB")

    # Portrait
    px, py = 540, 85
    canvas.paste(portrait, (px, py), portrait_mask)

    draw = ImageDraw.Draw(canvas)

    # Titres incrustés (gauche)
    y = 155
    for line in ("VOTRE", "BOUTIQUE", "EST-ELLE", "PIRATÉE ?"):
        draw_text_stroke(
            draw, (55, y), line,
            load_font(78 if line != "PIRATÉE ?" else 84, True),
            WHITE, BLACK, stroke_width=5, anchor="lm",
        )
        y += 88 if line != "EST-ELLE" else 82

    # Sous-titre orange
    y += 8
    draw.rounded_rectangle((48, y, 500, y + 72), radius=12, fill=ORANGE)
    draw.text((52, y + 36), "Le skimmer invisible de 2026", fill=WHITE, font=load_font(34, True), anchor="lm")
    y += 95

    for line in textwrap.wrap(
        "Connecté au BO ? Rien ne bouge. Vos clients, eux, paient ailleurs.",
        width=22,
    ):
        draw.text((52, y), line, fill=(235, 210, 200), font=load_font(30), anchor="lm")
        y += 40

    # CTA
    cta_y = SIZE - 130
    draw.rounded_rectangle((48, cta_y, 520, cta_y + 78), radius=40, fill=WHITE)
    draw.text((284, cta_y + 39), "TEST EN 5 MIN →", fill=RED, font=load_font(36, True), anchor="mm")

    # Signature
    draw.text((52, SIZE - 42), "arnaud-merigeau.fr", fill=ORANGE, font=load_font(26, True), anchor="lm")

    return canvas


def render_carousel_slide(slide: dict, date_label: str) -> Image.Image:
    canvas = Image.new("RGB", (SIZE, SIZE), BLACK)
    draw = ImageDraw.Draw(canvas)
    draw.rectangle((0, 0, SIZE, 8), fill=ORANGE)

    if slide.get("num"):
        draw.ellipse((80, 120, 200, 240), fill=ORANGE)
        num_font = load_font(72, True)
        num = slide["num"]
        tw = draw.textlength(num, font=num_font)
        draw.text((140 - tw / 2, 148), num, fill=WHITE, font=num_font)

    title_font = load_font(56, True)
    body_font = load_font(38)
    y = 300 if slide.get("num") else 200
    for line in textwrap.wrap(slide["title"], width=18):
        draw.text((80, y), line, fill=WHITE, font=title_font)
        y += 64
    y += 24
    for line in textwrap.wrap(slide["body"], width=26):
        draw.text((80, y), line, fill=(200, 200, 200), font=body_font)
        y += 48

    draw.text((80, SIZE - 80), f"arnaud-merigeau.fr · {date_label}", fill=ORANGE, font=load_font(28, True))
    return canvas


CAROUSEL_SLIDES = [
    {"title": "5 erreurs PrestaShop", "body": "En reprise de projet", "num": None},
    {"title": "Cron jamais configuré", "body": "Stocks faux, mails en retard, tâches planifiées mortes", "num": "1"},
    {"title": "Modules SEO en doublon", "body": "Meta contradictoires, sitemap pollué", "num": "2"},
    {"title": "Mails jamais testés", "body": "Le client commande, personne ne confirme", "num": "3"},
    {"title": "Zéro monitoring post-MàJ", "body": "On découvre la casse 3 semaines après", "num": "4"},
    {"title": "Overrides sans doc", "body": "Laquelle vous parle le plus ?", "num": "5"},
]


def main() -> None:
    OUT_DIR.mkdir(parents=True, exist_ok=True)
    out = OUT_DIR / "skimmer-2026-clickbait.png"
    render_skimmer_clickbait().save(out, "PNG", optimize=True)
    print(f"✓ {out.name}")

    for i, slide in enumerate(CAROUSEL_SLIDES, start=1):
        path = OUT_DIR / f"carrousel-erreurs-slide-{i:02d}.png"
        render_carousel_slide(slide, "30/08/2026").save(path, "PNG", optimize=True)
        print(f"✓ {path.name}")


if __name__ == "__main__":
    main()
