"""Spatial last-write-and-select v1. Oracle/control never imported by circuit.py."""
import hashlib, random, math
VERSION='spatial-last-write-select-v1'
DEADLINE=44
GAP_MIN,GAP_MAX=48,58

def seed(*parts):
    return int.from_bytes(hashlib.sha256('/'.join(map(str,parts)).encode()).digest()[:8],'big')

def events(value, count=64):
    rng=random.Random(value); out=[]; t=0
    for i in range(count):
        # Four initialization writes, then irregular overwrites and queries.
        kind='W' if i<4 or rng.random()<.4 else 'Q'
        if i>=count-32+sum(e['kind']=='Q' for e in out):kind='Q'
        a=i if i<4 else rng.randrange(4)
        out.append(dict(id=i,t=t,kind=kind,a=a,v=rng.choice([-1,1]) if kind=='W' else 0))
        t+=rng.randint(GAP_MIN,GAP_MAX)
    assert sum(e['kind']=='Q' for e in out)>=32
    return out

def oracle(stream,initial=None):
    bank=[0,0,0,0] if initial is None else list(initial); targets={}; last=[None]*4; ages={}
    for e in stream:
        if e['kind']=='W':bank[e['a']]=e['v'];last[e['a']]=e['t']
        else:
            targets[e['id']]=bank[e['a']]
            ages[e['id']]=None if last[e['a']] is None else e['t']-last[e['a']]
    return targets,ages

def reference(env,stream):
    """Independent analytical physical transducer, explicitly an oracle/control.
    It propagates external writes to a terminal timestamp and joins ideal retimed
    query paths. It does not consume constructed topology, holds, or predictions.
    """
    expected={}; histories=[[] for _ in range(4)]
    def dist(u,v):
        return max(1,math.ceil(sum((x-y)**2 for x,y in zip(env['sites'][u]['position'],env['sites'][v]['position']))**.5))
    times={}
    for a in range(4):
        root=dist('P',f'F{a}')
        totals={}
        for ch,n in [('M',env['m']),('C',env['r'])]:
            chain=[f'F{a}']+[f'{ch}{a}_{i}' for i in range(1,n+1)]+[f'G{a}']
            totals[ch]=sum(dist(x,y) for x,y in zip(chain,chain[1:]))
        # Writes terminate at the last latch, without the final latch->gate edge.
        write_delay=root+totals['M']-dist(f'M{a}_{env["m"]}',f'G{a}')
        times[a]=(root+max(totals.values()),write_delay)
    for e in stream:
        a=e['a'];lat,wd=times[a]
        if e['kind']=='W':histories[a].append((e['t']+wd,e['v']))
        else:
            settled=[v for t,v in histories[a] if t<=e['t']]
            expected[e['id']]=dict(value=settled[-1] if settled else 0,t=e['t']+lat,latency=lat)
    symbolic,_=oracle(stream)
    assert all(x['value']==symbolic[k] and 1<=x['latency']<=DEADLINE for k,x in expected.items())
    return expected

def score(e,target,responses):
    matching=[r for r in responses if r[0]==e['id']]
    within=[r for r in matching if e['t']+1<=r[1]<=e['t']+DEADLINE]
    correct=len(matching)==1 and matching[0][2]==target
    ontime=correct and len(within)==1
    failure='ok' if ontime else ('missing' if not matching else 'duplicate' if len(matching)>1 else 'incorrect' if not correct else 'late')
    return dict(correct=int(correct),success=int(ontime),failure=failure,
        latency=matching[0][1]-e['t'] if len(matching)==1 else '',responses=matching,
        missed_deadline=int(not within))
