#!/usr/bin/env python3
"""
Image post-processing toolkit for the creative pipeline.
Handles common fixes that don't require full regeneration.

Usage:
  python3 image-postprocess.py flatten-bg input.png output.png --color "#FF6B35"
  python3 image-postprocess.py upscale input.png output.png --factor 2
  python3 image-postprocess.py color-shift input.png output.png --hue 15 --saturation 1.1
  python3 image-postprocess.py crop input.png output.png --aspect 16:9
  python3 image-postprocess.py info input.png
"""

import argparse
import sys
import os

def ensure_deps():
    """Check dependencies are available."""
    try:
        from PIL import Image
        import numpy as np
        return True
    except ImportError:
        print("Missing dependencies. Install with:")
        print("  uv pip install Pillow numpy")
        print("Or use the existing venv: source /tmp/slides_env/bin/activate")
        return False

def flatten_bg(input_path, output_path, color_hex="#FFFFFF", tolerance=30):
    """Replace background with a solid color. Detects the dominant edge color as background."""
    from PIL import Image
    import numpy as np
    
    img = Image.open(input_path).convert("RGBA")
    arr = np.array(img)
    
    # Parse target color
    color_hex = color_hex.lstrip('#')
    target = np.array([int(color_hex[i:i+2], 16) for i in (0, 2, 4)])
    
    # Sample edges to find background color
    h, w = arr.shape[:2]
    edge_pixels = np.concatenate([
        arr[0, :, :3],           # top row
        arr[-1, :, :3],          # bottom row
        arr[:, 0, :3],           # left col
        arr[:, -1, :3],          # right col
    ])
    
    # Most common edge color (rough background detection)
    from collections import Counter
    colors = [tuple(p) for p in edge_pixels]
    bg_color = np.array(Counter(colors).most_common(1)[0][0])
    
    # Create mask: pixels close to detected background
    diff = np.sqrt(np.sum((arr[:, :, :3].astype(float) - bg_color.astype(float)) ** 2, axis=2))
    mask = diff < tolerance
    
    # Replace background pixels with target color
    result = arr.copy()
    result[mask, 0] = target[0]
    result[mask, 1] = target[1]
    result[mask, 2] = target[2]
    result[mask, 3] = 255  # fully opaque
    
    Image.fromarray(result).convert("RGB").save(output_path, quality=95)
    print(f"✅ Background flattened → {output_path}")
    print(f"   Detected BG color: rgb{tuple(bg_color)}, replaced with #{color_hex.upper()}")

def upscale(input_path, output_path, factor=2):
    """Simple upscale using Lanczos resampling."""
    from PIL import Image
    
    img = Image.open(input_path)
    new_size = (img.width * factor, img.height * factor)
    result = img.resize(new_size, Image.LANCZOS)
    result.save(output_path, quality=95)
    print(f"✅ Upscaled {factor}x → {output_path} ({new_size[0]}x{new_size[1]})")

def color_shift(input_path, output_path, hue_shift=0, saturation_mult=1.0, brightness_mult=1.0):
    """Adjust hue, saturation, and brightness."""
    from PIL import Image, ImageEnhance
    
    img = Image.open(input_path)
    
    if saturation_mult != 1.0:
        enhancer = ImageEnhance.Color(img)
        img = enhancer.enhance(saturation_mult)
    
    if brightness_mult != 1.0:
        enhancer = ImageEnhance.Brightness(img)
        img = enhancer.enhance(brightness_mult)
    
    if hue_shift != 0:
        # Convert to HSV, shift hue, convert back
        import numpy as np
        arr = np.array(img.convert("HSV"))
        arr[:, :, 0] = (arr[:, :, 0].astype(int) + hue_shift) % 256
        img = Image.fromarray(arr, "HSV").convert("RGB")
    
    img.save(output_path, quality=95)
    print(f"✅ Color adjusted → {output_path}")
    print(f"   Hue shift: {hue_shift}, Saturation: {saturation_mult}x, Brightness: {brightness_mult}x")

def crop_aspect(input_path, output_path, aspect="16:9"):
    """Crop to target aspect ratio (center crop)."""
    from PIL import Image
    
    img = Image.open(input_path)
    w, h = img.size
    
    target_w, target_h = map(int, aspect.split(":"))
    target_ratio = target_w / target_h
    current_ratio = w / h
    
    if current_ratio > target_ratio:
        # Too wide — crop width
        new_w = int(h * target_ratio)
        left = (w - new_w) // 2
        img = img.crop((left, 0, left + new_w, h))
    else:
        # Too tall — crop height
        new_h = int(w / target_ratio)
        top = (h - new_h) // 2
        img = img.crop((0, top, w, top + new_h))
    
    img.save(output_path, quality=95)
    print(f"✅ Cropped to {aspect} → {output_path} ({img.size[0]}x{img.size[1]})")

def info(input_path):
    """Print image metadata."""
    from PIL import Image
    
    img = Image.open(input_path)
    file_size = os.path.getsize(input_path)
    print(f"📊 Image Info: {input_path}")
    print(f"   Size: {img.size[0]}x{img.size[1]}")
    print(f"   Mode: {img.mode}")
    print(f"   Format: {img.format}")
    print(f"   File size: {file_size / 1024:.1f} KB ({file_size / 1024 / 1024:.2f} MB)")
    
    # Sample dominant colors
    import numpy as np
    from collections import Counter
    arr = np.array(img.convert("RGB"))
    # Sample 1000 random pixels
    flat = arr.reshape(-1, 3)
    indices = np.random.choice(len(flat), min(1000, len(flat)), replace=False)
    sampled = flat[indices]
    # Quantize to reduce color space
    quantized = (sampled // 32) * 32
    colors = Counter(map(tuple, quantized)).most_common(5)
    print(f"   Dominant colors (approx):")
    for c, count in colors:
        pct = count / len(indices) * 100
        print(f"     rgb{c} — {pct:.0f}%")

def main():
    parser = argparse.ArgumentParser(description="Image post-processing toolkit")
    sub = parser.add_subparsers(dest="command")
    
    # flatten-bg
    p = sub.add_parser("flatten-bg", help="Replace background with solid color")
    p.add_argument("input", help="Input image path")
    p.add_argument("output", help="Output image path")
    p.add_argument("--color", default="#FFFFFF", help="Target background color (hex)")
    p.add_argument("--tolerance", type=int, default=30, help="Color similarity tolerance")
    
    # upscale
    p = sub.add_parser("upscale", help="Upscale image")
    p.add_argument("input", help="Input image path")
    p.add_argument("output", help="Output image path")
    p.add_argument("--factor", type=int, default=2, help="Scale factor")
    
    # color-shift
    p = sub.add_parser("color-shift", help="Adjust colors")
    p.add_argument("input", help="Input image path")
    p.add_argument("output", help="Output image path")
    p.add_argument("--hue", type=int, default=0, help="Hue shift (0-255)")
    p.add_argument("--saturation", type=float, default=1.0, help="Saturation multiplier")
    p.add_argument("--brightness", type=float, default=1.0, help="Brightness multiplier")
    
    # crop
    p = sub.add_parser("crop", help="Crop to aspect ratio")
    p.add_argument("input", help="Input image path")
    p.add_argument("output", help="Output image path")
    p.add_argument("--aspect", default="16:9", help="Target aspect ratio (e.g., 16:9, 3:4)")
    
    # info
    p = sub.add_parser("info", help="Show image metadata")
    p.add_argument("input", help="Input image path")
    
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        return
    
    if not ensure_deps():
        sys.exit(1)
    
    if args.command == "flatten-bg":
        flatten_bg(args.input, args.output, args.color, args.tolerance)
    elif args.command == "upscale":
        upscale(args.input, args.output, args.factor)
    elif args.command == "color-shift":
        color_shift(args.input, args.output, args.hue, args.saturation, args.brightness)
    elif args.command == "crop":
        crop_aspect(args.input, args.output, args.aspect)
    elif args.command == "info":
        info(args.input)

if __name__ == "__main__":
    main()
