"""
Swarm Blackboard — in-process dict with file persistence for cross-agent coordination.

All agents (Macro Commander, Micro Sniper, Risk Commissar) read/write shared
state through a Blackboard instance, backed by a JSON file for crash recovery.
"""

from __future__ import annotations

import json
import os
import pathlib
import threading
import time
from typing import Any, Optional


class Blackboard(dict):
    """Dict-backed blackboard with JSON file persistence.

    Each section (e.g. "Macro_Commander") is a nested dict stored under a
    top-level key.  The optional _file_path auto-saves on every write.
    """

    def __init__(self, file_path: Optional[str] = None):
        super().__init__()
        self.file_path: Optional[str] = file_path
        self._lock = threading.Lock()
        if file_path:
            self._load()

    def update(self, namespace: str, key: str, value: Any) -> bool:
        with self._lock:
            section = self.setdefault(namespace, {})
            if not isinstance(section, dict):
                section = {}
                self[namespace] = section
            section[key] = value
            self._save()
            return True

    def add_log(self, role: str, msg_type: str, text: str) -> None:
        with self._lock:
            section = self.setdefault(role, {})
            log_list = section.setdefault("_logs", [])
            log_list.append({
                "ts": time.time(),
                "type": msg_type,
                "text": text,
            })
            if len(log_list) > 200:
                section["_logs"] = log_list[-200:]
            self._save()

    def _ensure(self) -> Blackboard:
        return self

    def _load(self) -> None:
        if not self.file_path:
            return
        try:
            p = pathlib.Path(self.file_path)
            if p.exists():
                raw = p.read_text(encoding="utf-8")
                if raw.strip():
                    data = json.loads(raw)
                    if isinstance(data, dict):
                        self.clear()
                        self.update(data)
        except Exception:
            pass

    def _save(self) -> None:
        if not self.file_path:
            return
        try:
            p = pathlib.Path(self.file_path)
            p.parent.mkdir(parents=True, exist_ok=True)
            p.write_text(json.dumps(dict(self), ensure_ascii=False, default=str), encoding="utf-8")
        except Exception:
            pass


def _resolve_default_blackboard_path() -> str:
    try:
        import config_manager
        d = config_manager.get_data_dir() / "bridge" / "state"
        d.mkdir(parents=True, exist_ok=True)
        return str(d / "blackboard_state.json")
    except Exception:
        return str(pathlib.Path.home() / ".gold_autotrade" / "blackboard_state.json")


global_blackboard = Blackboard(_resolve_default_blackboard_path())
