"""CROWD result-worker seam: accepted observations -> existing FrameResult.

No scheduler, publisher, tracker, pixel retention or Event/Artifact ownership.
The caller must perform run/queue/late-result admission BEFORE process().
"""
from app.contracts.visualization import FrameResult, VisualizationCommand
from app.crowd_config import CROWD_COLORS, CROWD_MODEL, CROWD_NAMES, CrowdDisplayConfig
from app.crowd_scenario import Crowd


class CrowdResultProcessor:
    def __init__(self, engine: Crowd, *, camera_id=None, scenario_revision=None):
        if not isinstance(engine, Crowd):
            raise ValueError('CROWD result processing requires its own engine.')
        self.engine = engine
        self.camera_id = camera_id
        self.scenario_revision = scenario_revision
        self._closed = False

    def process(self, frame, observations, *, usable=True):
        if self._closed:
            raise RuntimeError('CROWD result processor is closed.')
        # Validate output identity before evaluate() can mutate the window.
        if self.camera_id is not None and (type(self.camera_id) not in (str, int)
                or str(self.camera_id) != frame.source_id):
            raise ValueError('CROWD camera/source mismatch.')
        evaluation = self.engine.evaluate(frame, observations, usable=usable)
        if not evaluation.accepted:
            return None
        representatives = {}
        for i in evaluation.indices:
            o = observations[i]
            old = representatives.get(o.class_id)
            if old is None or o.score > observations[old].score:
                representatives[o.class_id] = i  # Equal score keeps original index.
        commands = []
        for i in evaluation.indices:
            o = observations[i]
            label = CROWD_NAMES[o.class_id]
            if evaluation.estimate is not None and representatives[o.class_id] == i:
                n = (evaluation.estimate.person_count if o.class_id == 0
                     else evaluation.estimate.head_count)
                label += f' | {"P" if o.class_id == 0 else "H"}≈{n}'
            commands.append(VisualizationCommand(o, label,
                color=CROWD_COLORS[o.class_id], visible=True,
                track_id=None, event_ids=(), scenario=None))
        # Never pass nms_kept: legacy serialization of that field is Pose-specific.
        # Current boxes only; a previous count is not a previous detection.
        return FrameResult(frame, tuple(commands), events=(),
            scenario_config=CrowdDisplayConfig(self.engine.config),
            scenario_revision=self.scenario_revision, provider_model=CROWD_MODEL,
            camera_id=self.camera_id)

    def expire_idle(self):
        return False if self._closed else self.engine.expire_idle()

    def close(self):
        self.engine.clear()
        self._closed = True
