#!/usr/bin/env python3
"""Normalize site images: square canvas, HALAL badge + Kött Gård logo. Colors preserved."""

from __future__ import annotations

import argparse
import shutil
from pathlib import Path

from PIL import Image, ImageDraw, ImageFont

ROOT = Path(__file__).resolve().parents[1]
SITE = ROOT / "public" / "images" / "site"
BACKUP = SITE / "_originals"
LOGO_PATH = SITE / "logo.jpeg"
BRAND_NAME = "Kött Gård"

SIZE = (1400, 1400)
BG = (255, 255, 255)
BURGUNDY = (139, 31, 31)
GOLD = (212, 175, 55)

SKIP = {"logo.jpeg", "README.txt"}
SKIP_PATTERNS = (" copy", "-1.jpg")  # duplicate uploads from user
FILL_PRODUCT = 0.9
FILL_PAGE = 0.94

PAGE_IMAGES = {"hero.jpg", "about.jpg", "weekly-offers.jpg"}
CATEGORY_IMAGES = {
    "category-chicken.jpg",
    "category-beef.jpg",
    "category-lamb.jpg",
    "category-fish.jpg",
}


def load_font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
    paths = [
        "/System/Library/Fonts/Supplemental/Arial Bold.ttf"
        if bold
        else "/System/Library/Fonts/Supplemental/Arial.ttf",
        "/Library/Fonts/Arial.ttf",
    ]
    for p in paths:
        try:
            return ImageFont.truetype(p, size)
        except OSError:
            continue
    return ImageFont.load_default()


def preserve_colors(img: Image.Image) -> Image.Image:
    """Keep original photo pixels — no contrast, brightness, or color tweaks."""
    return img.convert("RGB")


def prep_logo(diameter: int) -> Image.Image:
    logo = Image.open(LOGO_PATH).convert("RGBA")
    w, h = logo.size
    side = min(w, h)
    logo = logo.crop(((w - side) // 2, (h - side) // 2, (w + side) // 2, (h + side) // 2))
    logo = logo.resize((diameter, diameter), Image.Resampling.LANCZOS)
    mask = Image.new("L", (diameter, diameter), 0)
    ImageDraw.Draw(mask).ellipse((0, 0, diameter - 1, diameter - 1), fill=255)
    logo.putalpha(mask)
    return logo


def draw_halal_badge(canvas: Image.Image, x: int, y: int, size: int = 130) -> None:
    layer = Image.new("RGBA", canvas.size, (0, 0, 0, 0))
    draw = ImageDraw.Draw(layer)

    draw.ellipse((x + 4, y + 5, x + size + 4, y + size + 5), fill=(0, 0, 0, 100))
    draw.ellipse((x - 2, y - 2, x + size + 2, y + size + 2), fill=(*GOLD, 255))
    draw.ellipse((x + 6, y + 6, x + size - 6, y + size - 6), fill=(255, 255, 255, 255))
    draw.ellipse((x + 10, y + 10, x + size - 10, y + size - 10), outline=(*BURGUNDY, 255), width=4)

    f_ar = load_font(24, bold=True)
    f_halal = load_font(28, bold=True)
    f_sub = load_font(11, bold=True)

    ar = draw.textbbox((0, 0), "حلال", font=f_ar)
    draw.text((x + (size - ar[2] + ar[0]) // 2, y + 22), "حلال", fill=(*BURGUNDY, 255), font=f_ar)
    hl = draw.textbbox((0, 0), "HALAL", font=f_halal)
    draw.text((x + (size - hl[2] + hl[0]) // 2, y + 52), "HALAL", fill=(*BURGUNDY, 255), font=f_halal)
    ce = draw.textbbox((0, 0), "CERTIFIED", font=f_sub)
    draw.text((x + (size - ce[2] + ce[0]) // 2, y + 92), "CERTIFIED", fill=(*GOLD, 255), font=f_sub)

    canvas.alpha_composite(layer)


def draw_logo_badge(canvas: Image.Image, logo: Image.Image, x: int, y: int) -> None:
    d = logo.size[0]
    layer = Image.new("RGBA", canvas.size, (0, 0, 0, 0))
    draw = ImageDraw.Draw(layer)
    draw.ellipse((x + 3, y + 4, x + d + 3, y + d + 4), fill=(0, 0, 0, 90))
    draw.ellipse((x - 4, y - 4, x + d + 4, y + d + 4), fill=(255, 255, 255, 245), outline=(*GOLD, 255), width=3)
    canvas.alpha_composite(layer)
    canvas.alpha_composite(logo, (x, y))


def draw_brand_name(canvas: Image.Image, x: int, y: int) -> None:
    """Brand name pill beside the logo badge."""
    layer = Image.new("RGBA", canvas.size, (0, 0, 0, 0))
    draw = ImageDraw.Draw(layer)
    font = load_font(22, bold=True)
    bbox = draw.textbbox((0, 0), BRAND_NAME, font=font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
    pad_x, pad_y = 14, 8
    box = (x - tw - pad_x * 2, y, x - 8, y + th + pad_y * 2)
    draw.rounded_rectangle(box, radius=10, fill=(255, 255, 255, 235), outline=(*GOLD, 255), width=2)
    draw.text((box[0] + pad_x, box[1] + pad_y - 2), BRAND_NAME, fill=(*BURGUNDY, 255), font=font)
    canvas.alpha_composite(layer)


def already_branded(path: Path) -> bool:
    """Skip images already at catalog size (user uploads with logos baked in)."""
    with Image.open(path) as img:
        return img.size == SIZE


def should_skip(path: Path) -> bool:
    if path.name in SKIP or path.name.startswith("_"):
        return True
    return any(p in path.name for p in SKIP_PATTERNS)


def compose(source: Path, dest: Path, logo: Image.Image) -> None:
    photo = preserve_colors(Image.open(source))
    fill = FILL_PAGE if dest.name in PAGE_IMAGES else FILL_PRODUCT
    if dest.name in CATEGORY_IMAGES:
        fill = 0.92

    canvas = Image.new("RGBA", SIZE, (*BG, 255))
    max_side = int(SIZE[0] * fill)
    photo.thumbnail((max_side, max_side), Image.Resampling.LANCZOS)

    shadow = Image.new("RGBA", photo.size, (0, 0, 0, 0))
    sh_draw = ImageDraw.Draw(shadow)
    sh_draw.rounded_rectangle(
        (8, 12, photo.width - 8, photo.height - 4),
        radius=18,
        fill=(0, 0, 0, 35),
    )
    px = (SIZE[0] - photo.width) // 2
    py = (SIZE[1] - photo.height) // 2 - 16
    canvas.alpha_composite(shadow, (px, py + 6))
    canvas.alpha_composite(photo.convert("RGBA"), (px, py))

    margin = 28
    draw_halal_badge(canvas, margin, margin)
    logo_size = 108
    logo_x = SIZE[0] - logo_size - margin
    logo_y = SIZE[1] - logo_size - margin
    draw_logo_badge(canvas, logo, logo_x, logo_y)
    draw_brand_name(canvas, logo_x, logo_y + logo_size // 2 - 12)

    canvas.convert("RGB").save(dest, "JPEG", quality=94, optimize=True, subsampling=0)


def ensure_catalog_files() -> None:
    pairs = [
        ("beef-steak.jpg", "beef-steak-2.jpg"),
        ("beef-nihari-2.jpg", "beef-nihari.jpg"),
        ("category-lamb.jpg", "lamb-shoulder.jpg"),
    ]
    for target, source in pairs:
        t, s = SITE / target, SITE / source
        if not t.exists() and s.exists():
            shutil.copy2(s, t)
            print(f"Created missing {target} from {source}")


def main() -> None:
    parser = argparse.ArgumentParser(description="Brand site images (colors preserved)")
    parser.add_argument("--force", action="store_true", help="Re-process even if already 1400×1400")
    parser.add_argument("--only", nargs="*", help="Process only these filenames")
    args = parser.parse_args()

    if not LOGO_PATH.exists():
        raise SystemExit(f"Missing logo: {LOGO_PATH}")

    BACKUP.mkdir(exist_ok=True)
    ensure_catalog_files()

    logo = prep_logo(108)
    files = sorted(SITE.glob("*.jpg"))
    processed = 0
    skipped = 0

    for path in files:
        if should_skip(path):
            continue
        if args.only and path.name not in args.only:
            continue
        if not args.force and already_branded(path):
            print(f"○ {path.name} (already branded, skipped)")
            skipped += 1
            continue

        backup = BACKUP / path.name
        if not backup.exists():
            shutil.copy2(path, backup)
        source = backup if backup.exists() else path
        compose(source, path, logo)
        print(f"✓ {path.name}")
        processed += 1

    print(f"\nDone — {processed} processed, {skipped} skipped. Originals in {BACKUP}")


if __name__ == "__main__":
    main()