from PIL import Image, ImageDraw, ImageFilter, ImageEnhance
from pathlib import Path
import math, random

SRC = Path('/home/ubuntu/.hermes/image_cache/img_22336c28cebc.jpeg')
OUT = Path('/home/ubuntu/.hermes/artifacts/living-panel-on-original-right.png')
GRID = Path('/home/ubuntu/.hermes/artifacts/living-original-grid.png')

img = Image.open(SRC).convert('RGB')
W,H = img.size

# Create grid helper for visual verification
small = img.copy()
d = ImageDraw.Draw(small, 'RGBA')
step=200
for x in range(0,W+1,step):
    d.line([(x,0),(x,H)], fill=(255,0,0,90), width=3 if x%400==0 else 1)
    d.text((x+8,20), str(x), fill=(255,0,0,220))
for y in range(0,H+1,step):
    d.line([(0,y),(W,y)], fill=(0,60,255,90), width=3 if y%400==0 else 1)
    d.text((20,y+8), str(y), fill=(0,60,255,220))
small.save(GRID, quality=92)

# Work at full resolution. Create a more realistic wood slat panel overlay.
base = img.convert('RGBA')

# Measurement logic:
# real wall 310cm wide x 255cm high. Panel 121cm x 250cm.
# In the photo the wall plane is slightly perspective-skewed; place the panel close to the right wall but still clear of the sofa/shelf.
# Coordinates chosen from photo analysis. Height is almost full wall (2.5cm top/bottom margin), width follows 121/250 aspect ratio in photo perspective.
# Target position is right-shifted versus the centered 94.5cm margin: right margin about 42-45cm in-world.
# Full panel quadrilateral on wall plane (top-left, top-right, bottom-right, bottom-left):
quad = [(1125, 365), (1730, 385), (1748, 3468), (1110, 3445)]

# Create panel image before perspective transform.
panel_w = 700
panel_h = 3300
panel = Image.new('RGBA', (panel_w, panel_h), (0,0,0,0))
pd = ImageDraw.Draw(panel, 'RGBA')

# Background warm oak base
pd.rectangle([0,0,panel_w,panel_h], fill=(174,122,70,255))
# Add vertical slats: 11 EPS strips, proportionally identical to user panels
slats=11
gap=3
slat_w=(panel_w - gap*(slats-1)) / slats
random.seed(4)
for i in range(slats):
    x0=round(i*(slat_w+gap))
    x1=round(x0+slat_w)
    # alternating tones for natural wood
    tone = random.randint(-14,14)
    color=(max(0,min(255,178+tone)), max(0,min(255,123+tone//2)), max(0,min(255,69+tone//3)), 255)
    pd.rectangle([x0,0,x1,panel_h], fill=color)
    # center highlight and side shadows for 3D slat shape
    pd.rectangle([x0,0,x0+2,panel_h], fill=(95,60,30,90))
    pd.rectangle([x1-3,0,x1,panel_h], fill=(70,45,25,110))
    pd.rectangle([x0+5,0,x0+8,panel_h], fill=(245,210,150,40))
    # wood grain: subtle vertical wavy strokes
    for k in range(8):
        gx = x0 + random.randint(5, max(6,int(slat_w)-6))
        pts=[]
        phase=random.random()*6.28
        amp=random.uniform(1.0,3.2)
        for yy in range(-50,panel_h+50,28):
            pts.append((gx + math.sin(yy/95+phase)*amp, yy))
        shade=(95+random.randint(0,35), 62+random.randint(0,25), 32+random.randint(0,12), random.randint(30,58))
        pd.line(pts, fill=shade, width=random.choice([1,1,2]))
    # occasional knot/variation, very subtle so it stays photorealistic
    if random.random()<0.32:
        cy=random.randint(350,panel_h-350); cx=random.randint(x0+12,x1-12)
        r=random.randint(12,24)
        pd.ellipse([cx-r,cy-r*2,cx+r,cy+r*2], outline=(92,56,28,40), width=2)

# vertical grooves between slats
for i in range(1, slats):
    x=round(i*slat_w+(i-0.5)*gap)
    pd.rectangle([x-2,0,x+2,panel_h], fill=(42,27,16,155))

# subtle global texture/noise using transparent speckles
noise = Image.new('RGBA', (panel_w,panel_h),(0,0,0,0))
nd=ImageDraw.Draw(noise,'RGBA')
for _ in range(6500):
    x=random.randrange(panel_w); y=random.randrange(panel_h)
    a=random.randrange(5,18)
    v=random.choice([-1,1])
    nd.point((x,y), fill=(255 if v>0 else 0, 230 if v>0 else 0, 180 if v>0 else 0, a))
panel = Image.alpha_composite(panel, noise)

# Perspective transform helper: PIL expects coefficients mapping output -> input.
def find_coeffs(pa, pb):
    # pa: destination points, pb: source points
    import numpy as np
    matrix=[]
    for p1,p2 in zip(pa,pb):
        matrix.append([p1[0], p1[1], 1, 0,0,0, -p2[0]*p1[0], -p2[0]*p1[1]])
        matrix.append([0,0,0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]])
    A=np.matrix(matrix, dtype=float)
    B=np.array(pb).reshape(8)
    res=np.linalg.solve(A,B)
    return np.array(res).reshape(8)

# Need numpy; if unavailable, fallback to simple resize paste.
try:
    coeffs=find_coeffs(quad, [(0,0),(panel_w,0),(panel_w,panel_h),(0,panel_h)])
    warped=panel.transform((W,H), Image.Transform.PERSPECTIVE, coeffs, Image.Resampling.BICUBIC)
except Exception as e:
    warped=Image.new('RGBA',(W,H),(0,0,0,0))
    bbox=(min(x for x,y in quad), min(y for x,y in quad), max(x for x,y in quad), max(y for x,y in quad))
    warped.alpha_composite(panel.resize((bbox[2]-bbox[0], bbox[3]-bbox[1]), Image.Resampling.BICUBIC), (bbox[0],bbox[1]))

# Create LED halo behind panel. Light comes from 5cm hidden offset; simulate warm spill around all edges.
mask = Image.new('L',(W,H),0)
md = ImageDraw.Draw(mask)
md.polygon(quad, fill=255)
# border-only halo: expand panel mask and subtract original slightly expanded? Use blurred strokes around polygon.
halo = Image.new('RGBA',(W,H),(0,0,0,0))
hd=ImageDraw.Draw(halo,'RGBA')
# draw thick warm polygon outline then blur to represent light bounced on wall
for width,alpha in [(90,45),(55,65),(28,80)]:
    hd.line(quad+[quad[0]], fill=(255,185,85,alpha), width=width, joint='curve')
halo = halo.filter(ImageFilter.GaussianBlur(34))
# ensure halo appears behind only, not over central panel too much by compositing first then panel on top

# Add panel drop shadow: small soft shadow offset right/down, panel raised ~5.5cm from wall
shadow = Image.new('RGBA',(W,H),(0,0,0,0))
sd=ImageDraw.Draw(shadow,'RGBA')
shifted=[(x+24,y+18) for x,y in quad]
sd.polygon(shifted, fill=(0,0,0,88))
shadow=shadow.filter(ImageFilter.GaussianBlur(32))

# Compose. First halo over wall, then shadow, then panel.
comp = base.copy()
comp = Image.alpha_composite(comp, halo)
comp = Image.alpha_composite(comp, shadow)
comp = Image.alpha_composite(comp, warped)

# Add subtle front highlight to match room lighting from left/window.
high = Image.new('RGBA',(W,H),(0,0,0,0))
# Clip gradient to panel
panel_mask = warped.getchannel('A')
hi = Image.new('RGBA',(W,H),(0,0,0,0))
hid=ImageDraw.Draw(hi,'RGBA')
# left edge light
for i in range(0,120):
    alpha=max(0,26-int(i*0.22))
    hid.line([(1115+i,365),(1110+i,3445)], fill=(255,230,180,alpha), width=2)
hi.putalpha(Image.composite(hi.getchannel('A'), Image.new('L',(W,H),0), panel_mask))
comp=Image.alpha_composite(comp,hi)

# Add small annotation note outside image? no, keep clean photomockup.
comp = comp.convert('RGB')
comp.save(OUT, quality=95)
print(OUT)
print(GRID)
