# messaging/message_bus.py

from threading import Lock

class MessageBus:
    def __init__(self):
        self._lock = Lock()
        self._store = {}
        self._subscribers = []

    def publish(self, key, value):
        callbacks = []
        with self._lock:
            self._store[key] = value
            for pattern, callback in self._subscribers:
                if self._match(pattern, key):
                    callbacks.append(callback)
        for callback in callbacks:
            try:
                callback(key, value)
            except Exception:
                # Isolate bus publisher from subscriber failures.
                continue

    def subscribe(self, pattern, callback):
        with self._lock:
            self._subscribers.append((pattern, callback))

    def _match(self, pattern, key):
        # Simple "+" wildcard matching
        pattern_parts = pattern.split("/")
        key_parts = key.split("/")

        if len(pattern_parts) != len(key_parts):
            return False

        for p, k in zip(pattern_parts, key_parts):
            if p == "+":
                continue
            if p != k:
                return False
        return True

    def get(self, key, default=None):
        with self._lock:
            return self._store.get(key, default)

    def snapshot(self):
        with self._lock:
            return self._store.copy()

    def clear(self):
        with self._lock:
            self._store.clear()

    def keys(self):
        with self._lock:
            return list(self._store.keys())

    def items(self):
        with self._lock:
            return list(self._store.items())
