"""Geometry/text helpers copied from the verified Pose comparison renderer."""
from PIL import Image, ImageDraw, ImageFont, ImageOps
from contract import HIGH, LOW, MUTED, EDGES
W,H=3200,1800
IW,IH=1856,1044
IX,IY=20,150
LIMIT=(0,0,W,H)
FONT={n:ImageFont.truetype("/font.ttc",n,index=1) for n in (22,24,26,28,30,32,34,40)}

def intersects(a,b):return a[0]<b[2] and b[0]<a[2] and a[1]<b[3] and b[1]<a[3]

def text(draw,rects,xy,value,size=28,color='#edf1f5',limit=LIMIT):
    value=str(value);box=draw.textbbox(xy,value,font=FONT[size])
    assert box[0]>=limit[0] and box[1]>=limit[1] and box[2]<=limit[2] and box[3]<=limit[3],('text overflow',value,box)
    assert not any(intersects(box,b) for b in rects),('text overlap',value,box)
    rects.append(box);draw.text(xy,value,font=FONT[size],fill=color)

def accent(draw,p,color):
    x,y=p;draw.ellipse((x-8,y-8,x+8,y+8),outline=tuple(color),width=2)

def overlay(image,people):
    fit=ImageOps.contain(image,(IW,IH));panel=Image.new('RGB',(IW,IH),'black')
    ox,oy=(IW-fit.width)//2,(IH-fit.height)//2;panel.paste(fit,(ox,oy));d=ImageDraw.Draw(panel)
    sx,sy=fit.width/image.width,fit.height/image.height
    def point(x,y):return (ox+min(fit.width-1,max(0,x*sx)),oy+min(fit.height-1,max(0,y*sy)))
    geometry=[];protected=[]
    for p in people:
        a,b=point(*p['bbox'][:2]),point(*p['bbox'][2:]);points=[point(*k[:2]) if s in ('HIGH','LOW') else None for k,s in zip(p['joints'],p['joint_states'])]
        geometry.append((p,(*a,*b),points))
        for xy in points:
            if xy:protected.append((xy[0]-9,xy[1]-9,xy[0]+9,xy[1]+9))
        for (j,k),s in zip(EDGES,p['edge_states']):
            if s:
                x,y=points[j],points[k];protected.append((min(x[0],y[0])-4,min(x[1],y[1])-4,max(x[0],y[0])+4,max(x[1],y[1])+4))
    labels=[];occupied=[];far_labels=0
    for p,b,points in geometry:
        name=p['identity'] if p['track_id'] is not None else '미추적 '+p['identity']
        label=f"{name}  {p['person_score']:.3f}"+('  #'+str(p['detail_slot']) if p['detail_slot'] else '')
        tb=d.textbbox((0,0),label,font=FONT[22]);lw,lh=tb[2]-tb[0]+14,tb[3]-tb[1]+10
        near=[(b[0],b[1]-lh-4),(b[2]-lw,b[1]-lh-4),(b[0],b[3]+4),(b[2]+5,b[1]),(b[0]-lw-5,b[1])]
        grid=[(x,y) for y in range(5,IH-lh,lh+5) for x in range(5,IW-lw,max(100,lw//2))]
        grid.sort(key=lambda p:(p[0]-b[0])**2+(p[1]-b[1])**2)
        chosen=None
        for x,y in near+grid:
            r=(x,y,x+lw,y+lh)
            if x<0 or y<0 or r[2]>=IW or r[3]>=IH:continue
            if any(intersects(r,o) for o in occupied) or any(intersects(r,o) for o in protected):continue
            chosen=r;break
        assert chosen is not None,('No safe label space',CLIP,p['identity'])
        occupied.append(chosen);labels.append((p,label,chosen,tb))
        near_distance=((chosen[0]-b[0])**2+(chosen[1]-b[1])**2)**.5
        if near_distance>50:
            far_labels+=1;d.line((chosen[0]+lw/2,chosen[1]+lh/2,(b[0]+b[2])/2,b[1]),fill=tuple(p['identity_color']),width=1)
        d.rectangle(b,outline='#ff5555' if p.get('fight_display') else '#aab4bf',width=5 if p.get('fight_display') else 2)
    for p,b,points in geometry:
        for (a,c),state in zip(EDGES,p['edge_states']):
            if state:d.line((*points[a],*points[c]),fill='#9cd3dd' if state=='HIGH' else '#b89d65',width=2)
        for xy,state in zip(points,p['joint_states']):
            if xy is None:continue
            x,y=xy;radius=3 if state=='HIGH' else 4;ring=radius+3
            d.ellipse((x-ring,y-ring,x+ring,y+ring),outline=tuple(p['identity_color']),width=1)
            d.ellipse((x-radius,y-radius,x+radius,y+radius),fill='#9cd3dd' if state=='HIGH' else '#b89d65')
    for p,label,r,tb in labels:
        d.rectangle(r,fill='#101820',outline=tuple(p['identity_color']),width=2)
        d.text((r[0]+7-tb[0],r[1]+5-tb[1]),label,font=FONT[22],fill='#ffffff')
    return panel,dict(label_boxes=occupied,label_count=len(labels),far_labels=far_labels,label_overlap=0,label_joint_edge_overlap=0)

