"""Single-process Overlay transaction owner; no Runtime connections."""

from copy import deepcopy
from pathlib import Path
from threading import RLock

import yaml

from app.runtime_state import write_yaml_atomic


class ConfigPersistenceError(RuntimeError):
    def __init__(self):
        super().__init__("Stream configuration could not be persisted.")


class StreamConfigStore:
    def __init__(self, path):
        self.path = path
        self._lock = RLock()

    def read(self):
        with self._lock:
            try:
                if not Path(self.path).exists():
                    return {"added": [], "removed": []}
                with open(self.path, encoding="utf-8") as handle:
                    data = yaml.safe_load(handle)
                if not isinstance(data, dict):
                    raise ValueError()
                added, removed = data.get("added", []), data.get("removed", [])
                if not isinstance(added, list) or not isinstance(removed, list):
                    raise ValueError()
                if any(not isinstance(item, dict) or not item.get("stream_id") for item in added):
                    raise ValueError()
                return {"added": added, "removed": [str(item) for item in removed]}
            except Exception:
                raise ConfigPersistenceError() from None

    def update(self, change):
        # STREAMAPPLY-01: Camera가 달라도 공유 파일의 read-modify-write는 하나의 transaction이다.
        with self._lock:
            data = deepcopy(self.read())
            change(data)
            try:
                write_yaml_atomic(self.path, data)
            except Exception:
                raise ConfigPersistenceError() from None
