#!/usr/bin/env python3
"""
Tatiana's embroidered patch composite — v3.
Best placement: shoulder area x=790, y=460.
Patch is explicitly off-white fabric, not color-matched to dark areas.
"""

from PIL import Image, ImageDraw, ImageFilter, ImageEnhance
import numpy as np

np.random.seed(7)

# Load images
base = Image.open("v1-03-mid-full-body.png").convert("RGBA")
logo_raw = Image.open("ff-logo-mark.png").convert("RGBA")

base_arr = np.array(base)
base_rgb = np.array(base.convert("RGB"), dtype=np.float32)

print(f"Base: {base.size}, Logo: {logo_raw.size}")

# ============================================================
# PLACEMENT
# ============================================================
PASTE_X = 785
PASTE_Y = 455
PATCH_W = 80
PATCH_H = 62

# Sample the area for lighting info
arm_region = base_rgb[PASTE_Y:PASTE_Y+PATCH_H, PASTE_X:PASTE_X+PATCH_W]
arm_lum = (arm_region[:,:,0] * 0.299 + arm_region[:,:,1] * 0.587 + arm_region[:,:,2] * 0.114)
arm_lum_norm = arm_lum / 255.0
avg_lum = arm_lum_norm.mean()
print(f"Arm avg luminance: {avg_lum:.2f}")

# ============================================================
# BUILD PATCH FABRIC
# Explicitly off-white — patches are sewn on, their own material
# ============================================================
# Base off-white color — warm (slightly yellow-cream)
FABRIC_R, FABRIC_G, FABRIC_B = 234, 228, 216

patch = Image.new("RGBA", (PATCH_W, PATCH_H), (FABRIC_R, FABRIC_G, FABRIC_B, 255))
patch_arr = np.array(patch, dtype=np.float32)

# ---- Fabric texture: fine weave noise ----
noise_fine = np.random.normal(0, 3.5, (PATCH_H, PATCH_W, 3))
noise_coarse = np.random.normal(0, 2.5, (PATCH_H // 5 + 1, PATCH_W // 5 + 1, 3))
noise_coarse = np.repeat(np.repeat(noise_coarse, 5, axis=0), 5, axis=1)[:PATCH_H, :PATCH_W]
patch_arr[:,:,:3] = np.clip(patch_arr[:,:,:3] + noise_fine + noise_coarse, 0, 255)

# ---- Apply suit lighting onto patch ----
# Scale luminance-based adjustment: bright areas stay bright, dark get darker
# This fakes the patch receiving the same light as the suit surface
light_adjust = 0.65 + 0.7 * arm_lum_norm  # range ~0.65–1.35
# Cap max brightness to prevent blown out
light_adjust = np.clip(light_adjust, 0.55, 1.2)[:, :, np.newaxis]
patch_arr[:,:,:3] = np.clip(patch_arr[:,:,:3] * light_adjust, 0, 255)

# ---- Edge darkening (patch has slight shadow at edges from thickness/stitching) ----
for d in range(5):
    fade = 1.0 - (5 - d) * 0.025
    patch_arr[d, :, :3] *= fade
    patch_arr[PATCH_H-1-d, :, :3] *= fade
    patch_arr[:, d, :3] *= fade
    patch_arr[:, PATCH_W-1-d, :3] *= fade

patch_arr[:,:,3] = 255
patch = Image.fromarray(np.clip(patch_arr, 0, 255).astype(np.uint8), "RGBA")

# ============================================================
# PROCESS LOGO → EMBROIDERY
# ============================================================
logo_area_w = PATCH_W - 20
logo_area_h = PATCH_H - 18
logo_copy = logo_raw.copy()
logo_copy.thumbnail((logo_area_w, logo_area_h), Image.LANCZOS)
lw, lh = logo_copy.size
print(f"Logo on patch: {lw}x{lh} (patch {PATCH_W}x{PATCH_H})")

logo_data = np.array(logo_copy).astype(np.float32)
r, g, b, a = logo_data[:,:,0], logo_data[:,:,1], logo_data[:,:,2], logo_data[:,:,3]
lum = r * 0.299 + g * 0.587 + b * 0.114

# Logo pixels = dark + has alpha
logo_mask = (lum < 130) & (a > 40)

# Build embroidery with thread texture
emb = np.zeros((lh, lw, 4), dtype=np.float32)

# Thread color: very dark charcoal (not pure black — threads have character)
thread_r, thread_g, thread_b = 16, 13, 9

# Horizontal thread sheen (stitches run horizontally)
sheen_h = np.sin(np.arange(lh)[:, None] * 2.5) * 8 + np.random.normal(0, 2, (lh, lw))
# Make sheen only affect logo pixels
emb[:,:,0] = logo_mask * (thread_r + sheen_h * 0.6)
emb[:,:,1] = logo_mask * (thread_g + sheen_h * 0.5)
emb[:,:,2] = logo_mask * (thread_b + sheen_h * 0.4)
emb[:,:,3] = logo_mask * 235  # slight translucency for thread

emb_img = Image.fromarray(np.clip(emb, 0, 255).astype(np.uint8), "RGBA")
# Soften slightly (thread edges aren't perfectly sharp)
emb_img = emb_img.filter(ImageFilter.GaussianBlur(0.5))

# Paste logo centered on patch
lx = (PATCH_W - lw) // 2
ly = (PATCH_H - lh) // 2
patch.paste(emb_img, (lx, ly), emb_img)

# ============================================================
# STITCH BORDER
# ============================================================
draw = ImageDraw.Draw(patch)
bm = 4  # border margin

# Thread colors
outer_stitch = (28, 24, 18, 210)
inner_stitch = (50, 44, 34, 160)

def draw_stitches(draw, x1, y1, x2, y2, fill, width=1, gap=3, length=4, orient='h'):
    if orient == 'h':
        for x in range(x1, x2, gap + length):
            draw.line([(x, y1), (min(x + length, x2), y2)], fill=fill, width=width)
    else:
        for y in range(y1, y2, gap + length):
            draw.line([(x1, y), (x2, min(y + length, y2))], fill=fill, width=width)

# Outer stitches
draw_stitches(draw, bm, bm, PATCH_W - bm, bm, outer_stitch, orient='h')
draw_stitches(draw, bm, PATCH_H - bm - 1, PATCH_W - bm, PATCH_H - bm - 1, outer_stitch, orient='h')
draw_stitches(draw, bm, bm, bm, PATCH_H - bm, outer_stitch, orient='v')
draw_stitches(draw, PATCH_W - bm - 1, bm, PATCH_W - bm - 1, PATCH_H - bm, outer_stitch, orient='v')

# Inner stitches (creates double-border effect)
draw_stitches(draw, bm + 4, bm + 4, PATCH_W - bm - 4, bm + 4, inner_stitch, orient='h', gap=2, length=3)
draw_stitches(draw, bm + 4, PATCH_H - bm - 5, PATCH_W - bm - 4, PATCH_H - bm - 5, inner_stitch, orient='h', gap=2, length=3)
draw_stitches(draw, bm + 4, bm + 4, bm + 4, PATCH_H - bm - 4, inner_stitch, orient='v', gap=2, length=3)
draw_stitches(draw, PATCH_W - bm - 5, bm + 4, PATCH_W - bm - 5, PATCH_H - bm - 4, inner_stitch, orient='v', gap=2, length=3)

# Very slight blur on whole patch for fabric integration feel
patch = patch.filter(ImageFilter.GaussianBlur(0.3))

# ============================================================
# COMPOSITE: SHADOW + PATCH
# ============================================================
result = base.copy()

# --- Shadow ---
shadow_layer = Image.new("RGBA", base.size, (0, 0, 0, 0))
shadow = Image.new("RGBA", (PATCH_W + 8, PATCH_H + 8), (0, 0, 0, 0))
# Build soft graduated shadow
for i in range(8):
    alpha = max(0, 40 - i * 5)
    sx, sy = i, i
    sw, sh = PATCH_W + 8 - i * 2, PATCH_H + 8 - i * 2
    if sw > 0 and sh > 0:
        rect_img = Image.new("RGBA", (sw, sh), (3, 3, 3, alpha))
        shadow.paste(rect_img, (sx, sy), rect_img)
shadow = shadow.filter(ImageFilter.GaussianBlur(1.5))
shadow_layer.paste(shadow, (PASTE_X - 2, PASTE_Y + 2), shadow)
result = Image.alpha_composite(result, shadow_layer)

# --- Patch ---
patch_layer = Image.new("RGBA", base.size, (0, 0, 0, 0))
patch_layer.paste(patch, (PASTE_X, PASTE_Y), patch)
result = Image.alpha_composite(result, patch_layer)

# ============================================================
# SAVE
# ============================================================
result_rgb = result.convert("RGB")
result_rgb.save("tatiana-patch-v2.jpg", quality=96)
print(f"✓ Saved: tatiana-patch-v2.jpg")

# Debug: 2x zoom crop showing context
debug_area = result_rgb.crop((680, 360, 950, 600))
debug_big = debug_area.resize((debug_area.width * 2, debug_area.height * 2), Image.LANCZOS)
debug_big.save("tatiana-patch-v2-debug.jpg", quality=95)
print(f"✓ Debug: tatiana-patch-v2-debug.jpg")

# Tight crop of just the patch
patch_only = result_rgb.crop((PASTE_X - 10, PASTE_Y - 10, PASTE_X + PATCH_W + 10, PASTE_Y + PATCH_H + 10))
patch_big = patch_only.resize((patch_only.width * 4, patch_only.height * 4), Image.LANCZOS)
patch_big.save("tatiana-patch-v2-zoom.jpg", quality=95)
print(f"✓ Patch zoom: tatiana-patch-v2-zoom.jpg")
