"""A short directed seed permits only new, observed motion of the same limb."""
from collections import deque
from math import hypot
from decision import passes


class SeedFollow:
    def __init__(self,cfg):self.cfg=cfg;self.states={};self.last_time=None

    def step(self,row):
        cfg=self.cfg;t=row['seconds']
        assert self.last_time is None or t>self.last_time
        self.last_time=t
        for key,s in list(self.states.items()):
            if t-s['time']>cfg['window']+1e-8:del self.states[key]
        pairs=[]
        for p in row['pairs']:
            token=p['token'];s=self.states.setdefault(token,dict(seeds={},history=deque(maxlen=40),time=t))
            if p['reset']:s['seeds'].clear();s['history'].clear()
            s['time']=t
            while s['history'] and t-s['history'][0][0]>cfg['window']+1e-8:s['history'].popleft()
            s['seeds']={k:v for k,v in s['seeds'].items() if t-v[0]<=cfg['seed_seconds']+1e-8}
            seed_updates={};passing=[]
            for f in p['features']:
                key=(f['actor'],f['limb']);seed=s['seeds'].get(key);role=None
                if passes(f,cfg):
                    role='DIRECTED_SEED'
                    if key not in seed_updates or f['approach']/f['elapsed']>seed_updates[key]['approach']/seed_updates[key]['elapsed']:seed_updates[key]=f
                elif seed and f['speed']+1e-12>=cfg['speed_min'] and f['near']<=cfg['near_max']+.05+1e-12 and (f['kind']!='foot' or f['vertical']<=cfg['foot_vertical_max']+1e-12):
                    delta=seed[1];den=hypot(*delta)*hypot(*f['delta'])
                    opposite=sum(a*b for a,b in zip(delta,f['delta']))/den if den>1e-12 else 1
                    if opposite<=-.15 or f['cosine']>=cfg['cosine_min']:
                        role='OBSERVED_RETURN_OR_CONTINUATION'
                if role:passing.append(dict(f,evidence_role=role))
            for key,f in seed_updates.items():s['seeds'][key]=(t,f['delta'])
            flags=[any(f['actor']==i for f in passing) for i in (0,1)]
            s['history'].append((t,flags));counts=[sum(flags[i] for _,flags in s['history']) for i in (0,1)]
            actors=[i for i in (0,1) if flags[i] and counts[i]>=cfg['min_samples']]
            pairs.append(dict(token=token,refs=p['refs'],orders=p['orders'],mode=p['mode'],
                candidate_state=p['candidate_state'],hold_age=p['hold_age'],reset=p['reset'],observable=bool(p['features']),
                raw=any(flags),hit=bool(actors),actors=actors,counts=counts,passing=passing,
                features_count=len(p['features']),seeds=len(s['seeds']),
                reason='CURRENT_OBSERVED_EVIDENCE' if actors else 'RECENT_COUNT_BELOW' if any(flags)
                else 'FEATURE_CONDITIONS_BELOW' if p['features'] else 'INSUFFICIENT_OBSERVATIONS'))
        return dict(pairs=pairs,hit=any(p['hit'] for p in pairs),raw=any(p['raw'] for p in pairs),
            observable=any(p['observable'] for p in pairs),quiet=bool(pairs) and all(p['observable'] for p in pairs)
            and not any(p['raw'] for p in pairs) and not row['ambiguous'] and not row['pairs_over_cap'])
