"""Synthetic CPU-only input; no camera, secret, service or network access."""
from copy import deepcopy
import threading
from types import SimpleNamespace

from app.contracts.frames import FrameEnvelope, DetectionObservation, PoseObservation
from app.multi_roi.model import CONTRACT

CROWD = dict(reference_count=1, safe_ratio=.25, caution_ratio=.5, warning_ratio=.75, danger_ratio=.9)
LEFT = [[0., 0.], [.5, 0.], [.5, 1.], [0., 1.]]


def request(*codes):
    return dict(contract=CONTRACT, cameraId=1, rtspUrl='rtsp://example.invalid/video',
        startWallTimeMs=1, rtpClockRate=90000, rois=[], rules=[dict(ruleId=i, roiId=0,
        scenarioCode=code, parameters=dict(CROWD) if code == 'CROWD' else {}) for i, code in enumerate(codes)])


def frame(i=0, pts=None, run='run'):
    return FrameEnvelope('server', '1', 'stream', run, 1, i,
                         i*100_000_000 if pts is None else pts, 1, 1280, 720)


def observation(f, model='RFDETRMedium', x=.2, score=.9, cls=0):
    return DetectionObservation(f, model, cls, score, (x-.05, .2, x+.05, .8))


def pose(o):
    return PoseObservation(o.frame, o.model_key, o.score, o.bbox_xyxy,
                           tuple((.5, .5, .9) for _ in range(17)))


class Manager:
    def __init__(self):
        self._commands = threading.RLock()
        self._groups = {}
        self.starts = 0
        self.fail = False

    def camera_stream_id(self, source):
        for sid, g in self._groups.items():
            if g.spec['source_id'] == source:
                return sid
        raise KeyError(source)

    def get(self, sid):
        return self._groups.get(sid)

    def _saved_spec(self, group):
        return deepcopy(group.spec)

    def apply_and_start(self, spec):
        group = self.get(spec['stream_id'])
        if group is None:
            group = SimpleNamespace(spec={}, observed_state='stopped', _pending_restart=None, run=0)
            self._groups[spec['stream_id']] = group
        if group.spec != spec or group.observed_state == 'stopped':
            self.starts += 1
            group.run += 1
        group.spec = deepcopy(spec)
        group.observed_state = 'error' if self.fail else 'running'
        return group

    def stop(self, sid):
        self._groups[sid].observed_state = 'stopped'
        return self._groups[sid]
