"""Display-only correspondence; never feeds evidence or notification admission."""
from math import dist


class DisplayHold:
    def __init__(self):
        self.clear()

    def clear(self):
        self.states = []
        self.last_pts = None
        self.status = {}

    def step(self, pts, bodies, current_orders, seconds):
        if self.last_pts is not None and pts <= self.last_pts:
            self.clear()
        self.last_pts = pts
        # Purge using the previous deadline before applying a longer policy.
        self.states = [s for s in self.states if pts <= s['until']]
        for s in self.states:
            s['until'] = s['hit'] + seconds
        self.states = [s for s in self.states if pts <= s['until']]
        choices = {}
        reverse = {}
        for i, b in enumerate(bodies):
            options = []
            for j, state in enumerate(self.states):
                old = state['body']
                stable = b['tid'] is not None and b['tid'] == old['tid']
                if not stable and pts - state['seen'] > .30:
                    continue
                size = max(b['height'], old['height']) / max(1, min(b['height'], old['height']))
                distance = dist(b['center'], old['center']) / max(1, (b['height'] + old['height']) / 2)
                if size > 1.8 or distance > .45:
                    continue
                option = (0 if stable else 1, distance, j)
                options.append(option)
                reverse.setdefault(j, []).append((option[0], option[1], i))
            choices[i] = sorted(options)

        def unique(options):
            return len(options) == 1 or options[1][0] > options[0][0] or options[1][1] - options[0][1] >= .06

        visible = set(current_orders)
        held = []
        current = set(current_orders)
        pending = []
        ambiguous = 0
        for i, b in enumerate(bodies):
            options = choices[i]
            state = None
            if options:
                j = options[0][2]
                contenders = sorted(reverse[j])
                if unique(options) and unique(contenders) and contenders[0][2] == i:
                    state = self.states[j]
                    state.update(body=b, seen=pts)
                else:
                    ambiguous += 1
            if b['order'] in current:
                if state is None:
                    state = dict(body=b, seen=pts)
                    pending.append(state)
                state.update(hit=pts, until=pts + seconds)
            elif state is not None and seconds > 0 and pts <= state['until']:
                visible.add(b['order'])
                held.append(dict(order=b['order'], age_seconds=pts-state['hit']))
        self.states = sorted(self.states + pending, key=lambda s: s['hit'], reverse=True)[:64]
        self.status = dict(hold_seconds=seconds, held=held, states=len(self.states),
                           ambiguous=ambiguous, reason='HELD_CURRENT_OBJECTS' if held else 'NO_HELD_MATCH')
        return sorted(visible)
