"""CHRONOS bridge - adapter between NEUROVAULT and CHRONOS storage.

This module uses real CHRONOS when installed and transparently falls back
to a local compatible implementation for development and testing.
"""

from __future__ import annotations

import csv
import hashlib
import json
import logging
import os
import sqlite3
import time
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Optional

logger = logging.getLogger(__name__)

try:
    import numpy as np
except Exception:  # pragma: no cover
    np = None  # type: ignore

try:  # pragma: no cover - covered when chronos is installed
    import chronos as _chronos_package
    from chronos import ChronosRepository as _ChronosRepository
    from chronos import Memory as _ChronosMemory
    from chronos import RecallResult as _ChronosRecallResult
    from chronos.models import Checkpoint as _ChronosCheckpoint

    CHRONOS_VERSION = str(getattr(_chronos_package, "__version__", "unknown"))
    HAS_CHRONOS = True
except Exception:  # pragma: no cover - main path in local tests
    CHRONOS_VERSION = "fallback"
    HAS_CHRONOS = False


if HAS_CHRONOS:  # pragma: no cover
    ChronosRepository = _ChronosRepository
    Memory = _ChronosMemory
    RecallResult = _ChronosRecallResult
    Checkpoint = _ChronosCheckpoint
else:

    @dataclass
    class Memory:
        id: bytes
        content: str
        source: str
        importance: float
        metadata: dict[str, Any]
        created_at: int

        @property
        def short_id(self) -> str:
            return self.id.hex()[:8]

    @dataclass
    class RecallResult:
        memory: Memory
        score: float
        match_type: str = "keyword"

    @dataclass
    class Checkpoint:
        id: bytes
        message: str
        created_at: int

        @property
        def short_id(self) -> str:
            return self.id.hex()[:8]

    @dataclass
    class _Persona:
        name: str
        id: bytes
        description: str = ""

    @dataclass
    class _MergeConflict:
        source: Memory
        target: Memory
        similarity: float

    @dataclass
    class _MergeResult:
        added: list[Memory] = field(default_factory=list)
        skipped: list[tuple[Memory, str]] = field(default_factory=list)
        conflicts: list[_MergeConflict] = field(default_factory=list)
        strategy: str = "semantic"

    class _PersonaManager:
        def __init__(self, name: str):
            default = self._make(name=name, description="Default persona")
            self._personas: dict[str, _Persona] = {default.name: default}
            self._active_name = default.name

        def active(self) -> _Persona:
            return self._personas[self._active_name]

        def create(
            self,
            name: str,
            description: str = "",
            fork_from: str | None = None,
        ) -> _Persona:
            if name in self._personas:
                return self._personas[name]
            if fork_from and fork_from not in self._personas:
                raise ValueError(f"Unknown persona: {fork_from}")

            persona = self._make(name=name, description=description)
            self._personas[name] = persona
            return persona

        def use(self, name: str) -> _Persona:
            if name not in self._personas:
                raise ValueError(f"Unknown persona: {name}")
            self._active_name = name
            return self._personas[name]

        def list(self) -> list[_Persona]:
            return list(self._personas.values())

        def delete(self, name: str, force: bool = False) -> None:
            if name not in self._personas:
                raise ValueError(f"Unknown persona: {name}")
            if name == self._active_name and not force:
                raise ValueError("Cannot delete active persona without force=True")
            if name == "default" and not force:
                raise ValueError("Cannot delete 'default' persona without force=True")

            del self._personas[name]
            if self._active_name not in self._personas:
                self._active_name = next(iter(self._personas.keys()))

        @staticmethod
        def _make(name: str, description: str = "") -> _Persona:
            payload = f"persona:{name}".encode("utf-8")
            return _Persona(name=name, id=hashlib.sha256(payload).digest(), description=description)

    class _LocalStorage:
        def __init__(self, db_path: Path):
            self._db_path = db_path
            self._db_path.parent.mkdir(parents=True, exist_ok=True)
            try:
                os.chmod(self._db_path.parent, 0o700)
            except Exception as exc:
                logger.debug("Unable to chmod storage directory %s: %s", self._db_path.parent, exc)
            self._conn = sqlite3.connect(str(db_path), check_same_thread=False)
            self._conn.row_factory = sqlite3.Row
            self._conn.execute("PRAGMA journal_mode = WAL")
            self._conn.execute("PRAGMA foreign_keys = ON")
            self._ensure_schema()
            try:
                os.chmod(self._db_path, 0o600)
            except Exception as exc:
                logger.debug("Unable to chmod storage file %s: %s", self._db_path, exc)

        @property
        def conn(self) -> sqlite3.Connection:
            return self._conn

        def close(self) -> None:
            self._conn.close()

        def _ensure_schema(self) -> None:
            self._conn.executescript(
                """
                CREATE TABLE IF NOT EXISTS memories (
                    id BLOB PRIMARY KEY,
                    persona_id BLOB NOT NULL,
                    content TEXT NOT NULL,
                    source TEXT NOT NULL,
                    importance REAL NOT NULL DEFAULT 0.5,
                    metadata TEXT NOT NULL DEFAULT '{}',
                    embedding BLOB,
                    created_at INTEGER NOT NULL,
                    is_active INTEGER NOT NULL DEFAULT 1
                );
                CREATE INDEX IF NOT EXISTS idx_memories_persona ON memories(persona_id);
                CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at DESC);
                CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(is_active);

                CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
                    content,
                    content='memories',
                    content_rowid='rowid'
                );

                CREATE TRIGGER IF NOT EXISTS memories_ai_fts AFTER INSERT ON memories BEGIN
                    INSERT INTO memories_fts(rowid, content) VALUES (new.rowid, new.content);
                END;

                CREATE TRIGGER IF NOT EXISTS memories_ad_fts AFTER DELETE ON memories BEGIN
                    INSERT INTO memories_fts(memories_fts, rowid, content)
                    VALUES ('delete', old.rowid, old.content);
                END;

                CREATE TRIGGER IF NOT EXISTS memories_au_fts AFTER UPDATE ON memories BEGIN
                    INSERT INTO memories_fts(memories_fts, rowid, content)
                    VALUES ('delete', old.rowid, old.content);
                    INSERT INTO memories_fts(rowid, content) VALUES (new.rowid, new.content);
                END;

                CREATE TABLE IF NOT EXISTS checkpoints (
                    id BLOB PRIMARY KEY,
                    message TEXT NOT NULL,
                    created_at INTEGER NOT NULL
                );

                CREATE TABLE IF NOT EXISTS events (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    event_type TEXT NOT NULL,
                    payload TEXT NOT NULL,
                    persona_id BLOB NOT NULL,
                    created_at INTEGER NOT NULL
                );
                CREATE INDEX IF NOT EXISTS idx_events_created_at ON events(created_at DESC);
                """
            )
            self._conn.commit()

        def get_memory(self, memory_id: bytes) -> Memory:
            row = self._conn.execute(
                "SELECT * FROM memories WHERE id = ?",
                (memory_id,),
            ).fetchone()
            if not row:
                raise KeyError("memory not found")
            return _row_to_memory(row)

        def get_active_memories(self, persona_id: bytes) -> list[Memory]:
            rows = self._conn.execute(
                """
                SELECT * FROM memories
                WHERE persona_id = ? AND is_active = 1
                ORDER BY created_at DESC
                """,
                (persona_id,),
            ).fetchall()
            return [_row_to_memory(r) for r in rows]

        def get_memories_with_embeddings(self, persona_id: bytes) -> list[tuple[bytes, np.ndarray]]:
            if np is None:
                return []
            rows = self._conn.execute(
                """
                SELECT id, embedding FROM memories
                WHERE persona_id = ? AND is_active = 1 AND embedding IS NOT NULL
                ORDER BY created_at DESC
                """,
                (persona_id,),
            ).fetchall()
            result: list[tuple[bytes, np.ndarray]] = []
            for row in rows:
                try:
                    emb = np.frombuffer(row["embedding"], dtype=np.float32).copy()
                    result.append((row["id"], emb))
                except Exception as exc:
                    logger.debug("Skipping invalid embedding row %s: %s", row["id"], exc)
                    continue
            return result

        def insert_event(self, event_type: str, payload: dict[str, Any], persona_id: bytes) -> None:
            self._conn.execute(
                """
                INSERT INTO events (event_type, payload, persona_id, created_at)
                VALUES (?, ?, ?, ?)
                """,
                (event_type, json.dumps(payload), persona_id, int(time.time() * 1000)),
            )
            self._conn.commit()

        def list_events(
            self,
            persona_id: bytes | None = None,
            event_type: str | None = None,
            limit: int = 100,
        ) -> list[dict[str, Any]]:
            conditions: list[str] = []
            params: list[Any] = []
            if persona_id is not None:
                conditions.append("persona_id = ?")
                params.append(persona_id)
            if event_type is not None:
                conditions.append("event_type = ?")
                params.append(event_type)
            where = " AND ".join(conditions) if conditions else "1 = 1"
            rows = self._conn.execute(
                f"""
                SELECT id, event_type, payload, persona_id, created_at
                FROM events
                WHERE {where}
                ORDER BY created_at DESC
                LIMIT ?
                """,
                tuple(params + [max(1, min(limit, 1000))]),
            ).fetchall()
            return [
                {
                    "id": int(row["id"]),
                    "event_type": str(row["event_type"]),
                    "payload": json.loads(row["payload"]) if row["payload"] else {},
                    "persona_id": row["persona_id"],
                    "created_at": int(row["created_at"]),
                }
                for row in rows
            ]

    def _row_to_memory(row: sqlite3.Row) -> Memory:
        return Memory(
            id=row["id"],
            content=row["content"],
            source=row["source"],
            importance=row["importance"],
            metadata=json.loads(row["metadata"]) if row["metadata"] else {},
            created_at=row["created_at"],
        )

    class ChronosRepository:
        """Minimal local implementation compatible with methods used by NEUROVAULT."""

        def __init__(self, name: str, db_path: Path):
            self.name = name
            self._db_path = db_path
            self._storage = _LocalStorage(db_path)
            self.persona = _PersonaManager("default")
            self._embedding = None

        @classmethod
        def _default_base(cls) -> str:
            return str(Path.home() / ".neurovault")

        @classmethod
        def init(cls, name: str, no_embedding: bool = False, base_dir: str | None = None):
            root = Path(base_dir or cls._default_base()) / name
            root.mkdir(parents=True, exist_ok=True)
            db_path = root / "neurovault.db"
            return cls(name, db_path)

        @classmethod
        def open(cls, name: str, base_dir: str | None = None):
            root = Path(base_dir or cls._default_base()) / name
            db_path = root / "neurovault.db"
            if not db_path.exists():
                raise FileNotFoundError(f"Vault not found: {name}")
            return cls(name, db_path)

        def remember(
            self,
            content: str,
            source: str,
            importance: float,
            metadata: dict[str, Any] | None = None,
        ) -> Memory:
            now = int(time.time() * 1000)
            persona_id = self.persona.active().id
            payload = f"{content}\x00{source}\x00{now}\x00{time.time_ns()}".encode("utf-8")
            memory_id = hashlib.sha256(payload).digest()
            self._storage.conn.execute(
                """
                INSERT INTO memories (id, persona_id, content, source, importance, metadata, created_at)
                VALUES (?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    memory_id,
                    persona_id,
                    content,
                    source,
                    max(0.0, min(float(importance), 1.0)),
                    json.dumps(metadata or {}),
                    now,
                ),
            )
            self._storage.conn.commit()
            memory = Memory(
                id=memory_id,
                content=content,
                source=source,
                importance=max(0.0, min(float(importance), 1.0)),
                metadata=metadata or {},
                created_at=now,
            )
            self._emit_event(
                "memory.created",
                {"memory_id": memory_id.hex(), "content": content[:200], "source": source},
            )
            return memory

        def recall(self, query: str, limit: int = 10, mode: str = "keyword") -> list[RecallResult]:
            persona_id = self.persona.active().id
            limit = max(1, min(limit, 200))

            if not query.strip():
                rows = self._storage.conn.execute(
                    """
                    SELECT * FROM memories
                    WHERE persona_id = ? AND is_active = 1
                    ORDER BY created_at DESC
                    LIMIT ?
                    """,
                    (persona_id, limit),
                ).fetchall()
                return [RecallResult(memory=_row_to_memory(r), score=1.0 / (i + 1), match_type=mode) for i, r in enumerate(rows)]

            try:
                rows = self._storage.conn.execute(
                    """
                    SELECT m.*, bm25(memories_fts) AS rank
                    FROM memories_fts
                    JOIN memories m ON m.rowid = memories_fts.rowid
                    WHERE memories_fts MATCH ?
                      AND m.persona_id = ?
                      AND m.is_active = 1
                    ORDER BY rank
                    LIMIT ?
                    """,
                    (query, persona_id, limit),
                ).fetchall()
            except sqlite3.OperationalError:
                rows = self._storage.conn.execute(
                    """
                    SELECT * FROM memories
                    WHERE persona_id = ? AND is_active = 1
                      AND lower(content) LIKE ?
                    ORDER BY created_at DESC
                    LIMIT ?
                    """,
                    (persona_id, f"%{query.lower()}%", limit),
                ).fetchall()

            results: list[RecallResult] = []
            for i, row in enumerate(rows, start=1):
                score = 1.0 / i
                if "rank" in row.keys() and row["rank"] is not None:
                    score = 1.0 / (1.0 + max(float(row["rank"]), 0.0))
                results.append(RecallResult(memory=_row_to_memory(row), score=score, match_type=mode))
            return results

        def checkpoint(self, message: str) -> Checkpoint:
            now = int(time.time() * 1000)
            payload = f"{message}\x00{now}\x00{time.time_ns()}".encode("utf-8")
            checkpoint_id = hashlib.sha256(payload).digest()
            self._storage.conn.execute(
                "INSERT INTO checkpoints (id, message, created_at) VALUES (?, ?, ?)",
                (checkpoint_id, message, now),
            )
            self._storage.conn.commit()
            self._emit_event(
                "checkpoint.created",
                {"checkpoint_id": checkpoint_id.hex(), "message": message},
            )
            return Checkpoint(id=checkpoint_id, message=message, created_at=now)

        def list_checkpoints(self, limit: int = 50) -> list[Checkpoint]:
            rows = self._storage.conn.execute(
                "SELECT id, message, created_at FROM checkpoints ORDER BY created_at DESC LIMIT ?",
                (max(1, min(limit, 1000)),),
            ).fetchall()
            return [Checkpoint(id=r["id"], message=r["message"], created_at=r["created_at"]) for r in rows]

        def forget(self, memory_id_hex: str, hard: bool = False) -> None:
            memory_id = bytes.fromhex(memory_id_hex)
            if hard:
                self._storage.conn.execute("DELETE FROM memories WHERE id = ?", (memory_id,))
            else:
                self._storage.conn.execute(
                    "UPDATE memories SET is_active = 0 WHERE id = ?",
                    (memory_id,),
                )
            self._storage.conn.commit()
            self._emit_event("memory.forgotten", {"memory_id": memory_id_hex, "hard": hard})

        def run_decay(self, persona_id: bytes | None = None) -> dict[str, int]:
            del persona_id
            return {"updated": 0, "archived": 0}

        def merge(
            self,
            source_persona: str,
            strategy: str = "semantic",
            threshold: float = 0.95,
            dry_run: bool = False,
        ) -> _MergeResult:
            del threshold
            active = self.persona.active()
            source = active if source_persona == active.name else None
            if source is None:
                personas = {p.name: p for p in self.persona.list()}
                source = personas.get(source_persona)
            if source is None:
                raise ValueError(f"Unknown source persona: {source_persona}")

            target = self.persona.active()
            if source.id == target.id:
                return _MergeResult(strategy=strategy)

            source_rows = self._storage.conn.execute(
                """
                SELECT * FROM memories
                WHERE persona_id = ? AND is_active = 1
                ORDER BY created_at ASC
                """,
                (source.id,),
            ).fetchall()
            target_rows = self._storage.conn.execute(
                """
                SELECT * FROM memories
                WHERE persona_id = ? AND is_active = 1
                ORDER BY created_at ASC
                """,
                (target.id,),
            ).fetchall()

            target_contents = {str(row["content"]).strip().lower() for row in target_rows}
            result = _MergeResult(strategy=strategy)

            for row in source_rows:
                memory = _row_to_memory(row)
                content_key = memory.content.strip().lower()
                if strategy != "additive" and content_key in target_contents:
                    result.skipped.append((memory, "exact_content_match"))
                    continue

                result.added.append(memory)
                if dry_run:
                    continue

                metadata = dict(memory.metadata)
                metadata["merged_from"] = source_persona
                now = int(time.time() * 1000)
                payload = f"{memory.content}\x00merge\x00{now}\x00{time.time_ns()}".encode("utf-8")
                memory_id = hashlib.sha256(payload).digest()

                self._storage.conn.execute(
                    """
                    INSERT INTO memories (id, persona_id, content, source, importance, metadata, created_at, is_active)
                    VALUES (?, ?, ?, ?, ?, ?, ?, 1)
                    """,
                    (
                        memory_id,
                        target.id,
                        memory.content,
                        "merge",
                        max(0.0, min(float(memory.importance), 1.0)),
                        json.dumps(metadata),
                        now,
                    ),
                )
                target_contents.add(content_key)
                self._emit_event(
                    "memory.merged",
                    {"memory_id": memory_id.hex(), "source_persona": source_persona},
                )

            if not dry_run:
                self._storage.conn.commit()
                self._emit_event(
                    "merge.completed",
                    {
                        "source_persona": source_persona,
                        "strategy": strategy,
                        "added": len(result.added),
                        "skipped": len(result.skipped),
                    },
                )
            return result

        def graph_neighbors(self, entity_name: str) -> list[tuple[Any, Any]]:
            del entity_name
            return []

        def graph_path(self, source: str, target: str) -> list[tuple[Any, str, Any]]:
            del source, target
            return []

        def graph_rebuild(self) -> None:
            return None

        def consolidate(self) -> list[Memory]:
            return []

        def list_events(
            self,
            persona_id: bytes | None = None,
            event_type: str | None = None,
            limit: int = 100,
        ) -> list[dict[str, Any]]:
            return self._storage.list_events(persona_id=persona_id, event_type=event_type, limit=limit)

        def _emit_event(self, event_type: str, payload: dict[str, Any]) -> None:
            try:
                persona_id = self.persona.active().id
                self._storage.insert_event(event_type, payload, persona_id)
            except Exception as exc:
                logger.debug("Chronos fallback event emission failed (%s): %s", event_type, exc)


class ChronosBridge:
    """Adapter: NEUROVAULT -> CHRONOS."""

    def __init__(self, repo: ChronosRepository):
        self._repo = repo

    @classmethod
    def from_name(cls, name: str, base_dir: str | None = None) -> "ChronosBridge":
        repo = ChronosRepository.open(name, base_dir=base_dir)
        return cls(repo)

    @classmethod
    def create(
        cls,
        name: str,
        no_embedding: bool = False,
        base_dir: str | None = None,
    ) -> "ChronosBridge":
        repo = ChronosRepository.init(name, no_embedding=no_embedding, base_dir=base_dir)
        return cls(repo)

    def store_memory(
        self,
        content: str,
        source: str,
        importance: float,
        metadata: dict[str, Any] | None = None,
        context: str | None = None,
    ) -> Memory:
        if context is not None:
            try:
                return self._repo.remember(
                    content=content,
                    source=source,
                    importance=importance,
                    metadata=metadata or {},
                    context=context,
                )
            except TypeError:
                pass
        return self._repo.remember(
            content=content,
            source=source,
            importance=importance,
            metadata=metadata or {},
        )

    def get_memory(self, memory_id: bytes) -> Memory:
        storage = getattr(self._repo, "_storage", None)
        if storage is not None and hasattr(storage, "get_memory"):
            return storage.get_memory(memory_id)
        get_memory = getattr(self._repo, "get_memory", None)
        if callable(get_memory):
            return get_memory(memory_id)
        raise AttributeError("CHRONOS repository has no get_memory accessor")

    def search_memories(self, query: str, limit: int, mode: str) -> list[RecallResult]:
        return self._repo.recall(query=query, limit=limit, mode=mode)

    def get_active_persona_id(self) -> bytes:
        persona = self._repo.persona.active()
        persona_id = getattr(persona, "id", None)
        if persona_id is None:
            raise RuntimeError("Active persona is missing an ID")
        return persona_id

    def get_active_persona_name(self) -> str:
        persona = self._repo.persona.active()
        name = getattr(persona, "name", None)
        return str(name) if name else "default"

    def list_personas(self) -> list[dict[str, Any]]:
        manager = getattr(self._repo, "persona", None)
        list_fn = getattr(manager, "list", None) if manager is not None else None
        if not callable(list_fn):
            active = self._repo.persona.active()
            pid = getattr(active, "id", None)
            return [
                {
                    "name": str(getattr(active, "name", "default")),
                    "id": pid.hex() if isinstance(pid, (bytes, bytearray)) else None,
                    "description": str(getattr(active, "description", "")),
                    "active": True,
                }
            ]

        active_name = self.get_active_persona_name()
        personas: list[dict[str, Any]] = []
        for persona in list_fn():
            pid = getattr(persona, "id", None)
            name = str(getattr(persona, "name", ""))
            personas.append(
                {
                    "name": name,
                    "id": pid.hex() if isinstance(pid, (bytes, bytearray)) else None,
                    "description": str(getattr(persona, "description", "")),
                    "active": name == active_name,
                }
            )
        personas.sort(key=lambda item: item["name"])
        return personas

    def create_persona(
        self,
        name: str,
        description: str = "",
        fork_from: str | None = None,
    ) -> dict[str, Any]:
        manager = getattr(self._repo, "persona", None)
        create_fn = getattr(manager, "create", None) if manager is not None else None
        if not callable(create_fn):
            raise RuntimeError("Persona manager unavailable")

        kwargs: dict[str, Any] = {"name": name}
        if description:
            kwargs["description"] = description
        if fork_from:
            kwargs["fork_from"] = fork_from

        try:
            persona = create_fn(**kwargs)
        except TypeError:
            # Fallback managers may support only name.
            persona = create_fn(name)

        pid = getattr(persona, "id", None)
        return {
            "name": str(getattr(persona, "name", name)),
            "id": pid.hex() if isinstance(pid, (bytes, bytearray)) else None,
            "description": str(getattr(persona, "description", description)),
            "active": str(getattr(persona, "name", name)) == self.get_active_persona_name(),
        }

    def use_persona(self, name: str) -> bool:
        manager = getattr(self._repo, "persona", None)
        use_fn = getattr(manager, "use", None) if manager is not None else None
        if not callable(use_fn):
            return False
        try:
            use_fn(name)
            return True
        except Exception as exc:
            logger.debug("Failed to switch persona to %s: %s", name, exc)
            return False

    def delete_persona(self, name: str, force: bool = False) -> bool:
        manager = getattr(self._repo, "persona", None)
        delete_fn = getattr(manager, "delete", None) if manager is not None else None
        if not callable(delete_fn):
            return False
        try:
            delete_fn(name, force=force)
            return True
        except TypeError:
            try:
                delete_fn(name)
                return True
            except Exception as exc:
                logger.debug("Failed to delete persona %s via fallback signature: %s", name, exc)
                return False
        except Exception as exc:
            logger.debug("Failed to delete persona %s: %s", name, exc)
            return False

    def merge_persona(
        self,
        source_persona: str,
        strategy: str = "semantic",
        threshold: float = 0.95,
        dry_run: bool = False,
    ) -> dict[str, Any]:
        fn = getattr(self._repo, "merge", None)
        if not callable(fn):
            return {
                "strategy": strategy,
                "added": 0,
                "skipped": 0,
                "conflicts": 0,
                "dry_run": dry_run,
                "error": "Merge API unavailable",
            }
        try:
            result = fn(
                source_persona=source_persona,
                strategy=strategy,
                threshold=threshold,
                dry_run=dry_run,
            )
        except TypeError:
            result = fn(source_persona, strategy, threshold, dry_run)
        except Exception as exc:
            return {
                "strategy": strategy,
                "added": 0,
                "skipped": 0,
                "conflicts": 0,
                "dry_run": dry_run,
                "error": str(exc),
            }

        if isinstance(result, dict):
            payload = dict(result)
            payload.setdefault("strategy", strategy)
            payload.setdefault("dry_run", dry_run)
            payload.setdefault("added", 0)
            payload.setdefault("skipped", 0)
            payload.setdefault("conflicts", 0)
            return payload

        added = len(getattr(result, "added", []) or [])
        skipped = len(getattr(result, "skipped", []) or [])
        conflicts = len(getattr(result, "conflicts", []) or [])
        return {
            "strategy": str(getattr(result, "strategy", strategy)),
            "added": added,
            "skipped": skipped,
            "conflicts": conflicts,
            "dry_run": dry_run,
        }

    def sync_push(self, peer_name: str, output_path: str) -> dict[str, Any]:
        fn = getattr(self._repo, "sync_push", None)
        if not callable(fn):
            return {
                "peer": peer_name,
                "output_path": output_path,
                "memories": 0,
                "checkpoints": 0,
                "entities": 0,
                "relationships": 0,
                "error": "Sync push API unavailable",
            }
        try:
            bundle = fn(peer_name=peer_name, output_path=output_path)
            return {
                "peer": peer_name,
                "output_path": output_path,
                "memories": len(getattr(bundle, "memories", []) or []),
                "checkpoints": len(getattr(bundle, "checkpoints", []) or []),
                "entities": len(getattr(bundle, "entities", []) or []),
                "relationships": len(getattr(bundle, "relationships", []) or []),
                "error": None,
            }
        except TypeError:
            try:
                bundle = fn(peer_name, output_path)
                return {
                    "peer": peer_name,
                    "output_path": output_path,
                    "memories": len(getattr(bundle, "memories", []) or []),
                    "checkpoints": len(getattr(bundle, "checkpoints", []) or []),
                    "entities": len(getattr(bundle, "entities", []) or []),
                    "relationships": len(getattr(bundle, "relationships", []) or []),
                    "error": None,
                }
            except Exception as exc:
                return {
                    "peer": peer_name,
                    "output_path": output_path,
                    "memories": 0,
                    "checkpoints": 0,
                    "entities": 0,
                    "relationships": 0,
                    "error": str(exc),
                }
        except Exception as exc:
            return {
                "peer": peer_name,
                "output_path": output_path,
                "memories": 0,
                "checkpoints": 0,
                "entities": 0,
                "relationships": 0,
                "error": str(exc),
            }

    def sync_pull(self, bundle_path: str, strategy: str = "newer_wins") -> dict[str, Any]:
        fn = getattr(self._repo, "sync_pull", None)
        if not callable(fn):
            return {
                "bundle_path": bundle_path,
                "strategy": strategy,
                "added": 0,
                "skipped": 0,
                "conflicts": 0,
                "error": "Sync pull API unavailable",
            }
        try:
            result = fn(bundle_path=bundle_path, strategy=strategy)
        except TypeError:
            try:
                result = fn(bundle_path, strategy)
            except Exception as exc:
                return {
                    "bundle_path": bundle_path,
                    "strategy": strategy,
                    "added": 0,
                    "skipped": 0,
                    "conflicts": 0,
                    "error": str(exc),
                }
        except Exception as exc:
            return {
                "bundle_path": bundle_path,
                "strategy": strategy,
                "added": 0,
                "skipped": 0,
                "conflicts": 0,
                "error": str(exc),
            }

        if isinstance(result, dict):
            payload = dict(result)
            payload.setdefault("bundle_path", bundle_path)
            payload.setdefault("strategy", strategy)
            payload.setdefault("added", 0)
            payload.setdefault("skipped", 0)
            payload.setdefault("conflicts", 0)
            payload.setdefault("error", None)
            return payload

        return {
            "bundle_path": bundle_path,
            "strategy": strategy,
            "added": len(getattr(result, "added", []) or []),
            "skipped": len(getattr(result, "skipped", []) or []),
            "conflicts": len(getattr(result, "conflicts", []) or []),
            "error": None,
        }

    def generate_key(self, name: str = "default") -> dict[str, Any]:
        fn = getattr(self._repo, "generate_key", None)
        if not callable(fn):
            return {"name": name, "fingerprint": None, "id": None, "trust_level": None, "error": "Key generation unavailable"}
        try:
            key = fn(name=name)
        except TypeError:
            try:
                key = fn(name)
            except Exception as exc:
                return {"name": name, "fingerprint": None, "id": None, "trust_level": None, "error": str(exc)}
        except Exception as exc:
            return {"name": name, "fingerprint": None, "id": None, "trust_level": None, "error": str(exc)}

        key_id = getattr(key, "id", None)
        return {
            "name": str(getattr(key, "name", name)),
            "fingerprint": str(getattr(key, "fingerprint", "")) or None,
            "id": key_id.hex() if isinstance(key_id, (bytes, bytearray)) else None,
            "trust_level": str(getattr(key, "trust_level", "")) or None,
            "error": None,
        }

    def verify_deep(self) -> dict[str, Any]:
        fn = getattr(self._repo, "verify_deep", None)
        if callable(fn):
            try:
                result = fn()
                if isinstance(result, dict):
                    out = dict(result)
                    out.setdefault("error", None)
                    return out
            except Exception as exc:
                return {
                    "memories_checked": 0,
                    "signatures_valid": 0,
                    "signatures_invalid": 0,
                    "unsigned": 0,
                    "hash_errors": 0,
                    "error": str(exc),
                }

        records = self.get_active_memories_with_metadata()
        return {
            "memories_checked": len(records),
            "signatures_valid": 0,
            "signatures_invalid": 0,
            "unsigned": len(records),
            "hash_errors": 0,
            "error": None,
        }

    def get_active_memories_with_metadata(self) -> list[dict[str, Any]]:
        storage = getattr(self._repo, "_storage", None)
        if storage is None or not hasattr(storage, "get_active_memories"):
            return []
        active = self._repo.persona.active()
        active_id = getattr(active, "id", None)
        if active_id is None:
            return []
        memories = storage.get_active_memories(active_id)
        return [
            {
                "id": m.id,
                "content": m.content,
                "importance": m.importance,
                "created_at": m.created_at,
                "source": m.source,
                "metadata": m.metadata,
            }
            for m in memories
        ]

    def get_recent_memories_with_embeddings(self, limit: int = 300) -> list[dict[str, Any]]:
        storage = getattr(self._repo, "_storage", None)
        if storage is None or not hasattr(storage, "get_memories_with_embeddings"):
            return []
        active = self._repo.persona.active()
        active_id = getattr(active, "id", None)
        if active_id is None:
            return []
        pairs = storage.get_memories_with_embeddings(active_id)
        result: list[dict[str, Any]] = []
        for memory_id, embedding in pairs[:limit]:
            try:
                mem = storage.get_memory(memory_id)
            except Exception as exc:
                logger.debug("Skipping embedding without memory payload %s: %s", memory_id.hex(), exc)
                continue
            result.append(
                {
                    "id": memory_id,
                    "embedding": embedding,
                    "content": mem.content,
                    "created_at": mem.created_at,
                }
            )
        return result

    def update_importance(self, memory_id: bytes, importance: float) -> None:
        storage = getattr(self._repo, "_storage", None)
        conn = getattr(storage, "conn", None)
        if conn is None:
            return
        conn.execute(
            "UPDATE memories SET importance = ? WHERE id = ?",
            (max(0.0, min(importance, 1.0)), memory_id),
        )
        conn.commit()

    def update_memory_metadata(self, memory_id: bytes, updates: dict[str, Any]) -> None:
        storage = getattr(self._repo, "_storage", None)
        conn = getattr(storage, "conn", None)
        if storage is None or conn is None:
            return
        mem = storage.get_memory(memory_id)
        metadata = dict(mem.metadata)
        metadata.update(updates)
        conn.execute(
            "UPDATE memories SET metadata = ? WHERE id = ?",
            (json.dumps(metadata), memory_id),
        )
        conn.commit()

    def checkpoint(self, message: str) -> Checkpoint:
        return self._repo.checkpoint(message)

    @property
    def repo(self) -> ChronosRepository:
        return self._repo

    def list_checkpoints(self, limit: int = 50) -> list[Checkpoint]:
        fn = getattr(self._repo, "log", None)
        if callable(fn):
            try:
                return fn(limit=limit)
            except Exception as exc:
                logger.debug("Repo log() unavailable; using storage fallback: %s", exc)

        fn = getattr(self._repo, "list_checkpoints", None)
        if callable(fn):
            try:
                return fn(limit=limit)
            except Exception as exc:
                logger.debug("Repo list_checkpoints() unavailable; using storage fallback: %s", exc)

        conn = getattr(getattr(self._repo, "_storage", None), "conn", None)
        if conn is None:
            return []
        try:
            rows = conn.execute(
                "SELECT id, message, created_at FROM checkpoints ORDER BY created_at DESC LIMIT ?",
                (max(1, min(limit, 1000)),),
            ).fetchall()
            return [Checkpoint(id=r["id"], message=r["message"], created_at=r["created_at"]) for r in rows]
        except Exception as exc:
            logger.debug("Checkpoint fallback query failed: %s", exc)
            return []

    def checkpoint_diff(self, ref1: str, ref2: str, limit: int = 50) -> dict[str, Any]:
        fn = getattr(self._repo, "diff", None)
        if callable(fn):
            try:
                raw = fn(ref1, ref2)
                return {
                    "ref1": str(getattr(raw, "ref1", ref1)),
                    "ref2": str(getattr(raw, "ref2", ref2)),
                    "added": [_memory_to_dict(m) for m in (getattr(raw, "added", []) or [])[:limit]],
                    "removed": [_memory_to_dict(m) for m in (getattr(raw, "removed", []) or [])[:limit]],
                }
            except Exception as exc:
                logger.debug("Repo diff() unavailable; using storage fallback: %s", exc)

        conn = getattr(getattr(self._repo, "_storage", None), "conn", None)
        if conn is None:
            return {"ref1": ref1, "ref2": ref2, "added": [], "removed": []}
        try:
            cp1 = self._resolve_checkpoint_ref(conn, ref1)
            cp2 = self._resolve_checkpoint_ref(conn, ref2)

            rows1 = conn.execute(
                "SELECT id FROM memories WHERE created_at < ?",
                (int(cp1["created_at"]),),
            ).fetchall()
            rows2 = conn.execute(
                "SELECT id FROM memories WHERE created_at <= ?",
                (int(cp2["created_at"]),),
            ).fetchall()
            ids1 = {row["id"] for row in rows1}
            ids2 = {row["id"] for row in rows2}

            added_ids = list(ids2 - ids1)[: max(1, limit)]
            removed_ids = list(ids1 - ids2)[: max(1, limit)]

            def _load(mid: bytes) -> dict[str, Any]:
                row = conn.execute(
                    """
                    SELECT id, content, source, importance, created_at
                    FROM memories WHERE id = ?
                    """,
                    (mid,),
                ).fetchone()
                if row is None:
                    return {"id": mid.hex(), "content": "", "source": "", "importance": 0.0, "created_at": 0}
                return {
                    "id": row["id"].hex() if isinstance(row["id"], (bytes, bytearray)) else str(row["id"]),
                    "content": str(row["content"]),
                    "source": str(row["source"]),
                    "importance": float(row["importance"]),
                    "created_at": int(row["created_at"]),
                }

            return {
                "ref1": ref1,
                "ref2": ref2,
                "added": [_load(mid) for mid in added_ids],
                "removed": [_load(mid) for mid in removed_ids],
            }
        except Exception as exc:
            logger.debug("Checkpoint diff fallback failed for %s..%s: %s", ref1, ref2, exc)
            return {"ref1": ref1, "ref2": ref2, "added": [], "removed": []}

    def create_milestone(self, name: str, ref: str = "HEAD", message: str = "") -> dict[str, Any]:
        fn = getattr(self._repo, "create_milestone", None)
        if callable(fn):
            try:
                milestone = fn(name=name, ref=ref, message=message)
                checkpoint_id = getattr(milestone, "checkpoint_id", None)
                return {
                    "name": str(getattr(milestone, "name", name)),
                    "checkpoint_id": (
                        checkpoint_id.hex() if isinstance(checkpoint_id, (bytes, bytearray)) else None
                    ),
                    "message": str(getattr(milestone, "message", message)),
                    "created_at": int(getattr(milestone, "created_at", int(time.time() * 1000))),
                }
            except Exception as exc:
                logger.debug("Repo create_milestone() unavailable; using storage fallback: %s", exc)

        conn = getattr(getattr(self._repo, "_storage", None), "conn", None)
        if conn is None:
            raise RuntimeError("Milestones unavailable")
        self._ensure_milestones_table(conn)
        checkpoint = self._resolve_checkpoint_ref(conn, ref)
        now = int(time.time() * 1000)
        milestone_id = hashlib.sha256(f"{name}\x00{checkpoint['id'].hex()}".encode("utf-8")).digest()
        conn.execute(
            """
            INSERT OR REPLACE INTO milestones (id, name, checkpoint_id, message, created_at)
            VALUES (?, ?, ?, ?, ?)
            """,
            (milestone_id, name, checkpoint["id"], message, now),
        )
        conn.commit()
        return {
            "name": name,
            "checkpoint_id": checkpoint["id"].hex(),
            "message": message,
            "created_at": now,
        }

    def list_milestones(self, limit: int = 100) -> list[dict[str, Any]]:
        fn = getattr(self._repo, "list_milestones", None)
        if callable(fn):
            try:
                milestones = fn()
                return [
                    {
                        "name": str(getattr(item, "name", "")),
                        "checkpoint_id": (
                            getattr(item, "checkpoint_id").hex()
                            if isinstance(getattr(item, "checkpoint_id", None), (bytes, bytearray))
                            else None
                        ),
                        "message": str(getattr(item, "message", "")),
                        "created_at": int(getattr(item, "created_at", 0)),
                    }
                    for item in milestones[: max(1, min(limit, 1000))]
                ]
            except Exception as exc:
                logger.debug("Repo list_milestones() unavailable; using storage fallback: %s", exc)

        conn = getattr(getattr(self._repo, "_storage", None), "conn", None)
        if conn is None:
            return []
        self._ensure_milestones_table(conn)
        rows = conn.execute(
            """
            SELECT name, checkpoint_id, message, created_at
            FROM milestones
            ORDER BY created_at DESC
            LIMIT ?
            """,
            (max(1, min(limit, 1000)),),
        ).fetchall()
        return [
            {
                "name": str(row["name"]),
                "checkpoint_id": (
                    row["checkpoint_id"].hex()
                    if isinstance(row["checkpoint_id"], (bytes, bytearray))
                    else None
                ),
                "message": str(row["message"] or ""),
                "created_at": int(row["created_at"]),
            }
            for row in rows
        ]

    def revert(self, ref: str, hard: bool = False) -> dict[str, Any]:
        fn = getattr(self._repo, "revert", None)
        if callable(fn):
            try:
                checkpoint = fn(ref=ref, hard=hard)
                cid = getattr(checkpoint, "id", None)
                return {
                    "id": cid.hex() if isinstance(cid, (bytes, bytearray)) else None,
                    "short_id": str(getattr(checkpoint, "short_id", "")),
                    "message": str(getattr(checkpoint, "message", "")),
                    "created_at": int(getattr(checkpoint, "created_at", 0)),
                    "ref": ref,
                    "hard": hard,
                }
            except Exception as exc:
                return {"ref": ref, "hard": hard, "error": str(exc)}

        conn = getattr(getattr(self._repo, "_storage", None), "conn", None)
        if conn is None:
            return {"ref": ref, "hard": hard, "error": "Revert unavailable"}
        try:
            checkpoint = self._resolve_checkpoint_ref(conn, ref)
            cutoff = int(checkpoint["created_at"])
            conn.execute("UPDATE memories SET is_active = 0 WHERE created_at > ?", (cutoff,))
            if hard:
                conn.execute("DELETE FROM memories WHERE created_at > ? AND is_active = 0", (cutoff,))
            conn.commit()
            return {
                "id": checkpoint["id"].hex(),
                "short_id": checkpoint["id"].hex()[:8],
                "message": str(checkpoint["message"]),
                "created_at": cutoff,
                "ref": ref,
                "hard": hard,
            }
        except Exception as exc:
            return {"ref": ref, "hard": hard, "error": str(exc)}

    def export_memories(self, path: str | Path, fmt: str = "json", since: int | None = None) -> None:
        out_path = Path(path)
        out_path.parent.mkdir(parents=True, exist_ok=True)

        native_export = getattr(self._repo, "export", None)
        if callable(native_export) and since is None:
            try:
                native_export(path=str(out_path), format=fmt)
                return
            except Exception as exc:
                logger.debug("Repo export() unavailable; using storage fallback: %s", exc)

        records = self.get_active_memories_with_metadata()
        if since is not None:
            records = [r for r in records if int(r.get("created_at", 0)) >= since]

        if fmt == "json":
            out_path.write_text(json.dumps(_json_safe(records), indent=2))
            return

        if fmt == "csv":
            with out_path.open("w", newline="") as handle:
                writer = csv.DictWriter(
                    handle,
                    fieldnames=["id", "created_at", "source", "importance", "content", "metadata"],
                )
                writer.writeheader()
                for rec in records:
                    writer.writerow(
                        {
                            "id": rec["id"].hex() if isinstance(rec["id"], (bytes, bytearray)) else rec["id"],
                            "created_at": rec.get("created_at"),
                            "source": rec.get("source"),
                            "importance": rec.get("importance"),
                            "content": rec.get("content"),
                            "metadata": json.dumps(rec.get("metadata", {})),
                        }
                    )
            return

        raise ValueError(f"Unsupported export format: {fmt}")

    def import_memories(self, path: str | Path) -> dict[str, Any]:
        in_path = Path(path)
        if not in_path.exists():
            return {"imported": 0, "skipped": 0, "errors": [f"File not found: {in_path}"]}

        native_import = getattr(self._repo, "import_memories", None)
        if callable(native_import):
            try:
                result = native_import(str(in_path))
                if isinstance(result, dict):
                    imported = int(result.get("imported", result.get("added", 0)))
                    skipped = int(result.get("skipped", 0))
                    errors = list(result.get("errors", []))
                    return {"imported": imported, "skipped": skipped, "errors": errors}
                imported = len(getattr(result, "added", []) or [])
                skipped = len(getattr(result, "skipped", []) or [])
                conflicts = len(getattr(result, "conflicts", []) or [])
                errors = []
                if conflicts > 0:
                    errors.append(f"{conflicts} merge conflicts")
                return {"imported": imported, "skipped": skipped, "errors": errors}
            except Exception as exc:
                logger.debug("Repo import_memories() unavailable; using storage fallback: %s", exc)

        try:
            payload = json.loads(in_path.read_text())
        except Exception as exc:
            return {"imported": 0, "skipped": 0, "errors": [str(exc)]}

        imported = 0
        skipped = 0
        errors: list[str] = []

        entries: list[Any]
        if isinstance(payload, list):
            entries = payload
        elif isinstance(payload, dict) and isinstance(payload.get("memories"), list):
            entries = payload["memories"]
        else:
            return {
                "imported": 0,
                "skipped": 0,
                "errors": ["Expected top-level JSON list or object with 'memories'"],
            }

        for entry in entries:
            if not isinstance(entry, dict):
                skipped += 1
                continue
            content = str(entry.get("content", "")).strip()
            if not content:
                skipped += 1
                continue
            source = str(entry.get("source", "import"))
            importance = float(entry.get("importance", 0.5))
            metadata = entry.get("metadata", {})
            if not isinstance(metadata, dict):
                metadata = {}
            try:
                self.store_memory(content=content, source=source, importance=importance, metadata=metadata)
                imported += 1
            except Exception as exc:
                errors.append(str(exc))

        return {"imported": imported, "skipped": skipped, "errors": errors}

    def run_decay(self) -> dict[str, int]:
        fn = getattr(self._repo, "run_decay", None)
        if callable(fn):
            try:
                result = fn()
                if isinstance(result, dict):
                    return {str(k): int(v) for k, v in result.items()}
            except Exception as exc:
                logger.debug("Repo run_decay() unavailable; returning empty decay stats: %s", exc)
        return {"updated": 0, "archived": 0}

    def rebuild_graph(self) -> bool:
        fn = getattr(self._repo, "graph_rebuild", None)
        if callable(fn):
            try:
                fn()
                return True
            except Exception as exc:
                logger.debug("Graph rebuild failed: %s", exc)
                return False
        return False

    def graph_neighbors(self, entity_name: str) -> list[tuple[Any, Any]]:
        fn = getattr(self._repo, "graph_neighbors", None)
        if callable(fn):
            try:
                return list(fn(entity_name))
            except Exception as exc:
                logger.debug("Graph neighbors failed for %s: %s", entity_name, exc)
                return []
        return []

    def graph_path(self, source: str, target: str) -> list[tuple[Any, str, Any]]:
        fn = getattr(self._repo, "graph_path", None)
        if callable(fn):
            try:
                return list(fn(source, target))
            except Exception as exc:
                logger.debug("Graph path failed for %s -> %s: %s", source, target, exc)
                return []
        return []

    def consolidate_native(self) -> list[Memory]:
        fn = getattr(self._repo, "consolidate", None)
        if callable(fn):
            try:
                return list(fn())
            except Exception as exc:
                logger.debug("Native consolidation call failed: %s", exc)
                return []
        return []

    def list_events(
        self,
        limit: int = 100,
        event_type: str | None = None,
    ) -> list[dict[str, Any]]:
        storage = getattr(self._repo, "_storage", None)
        if storage is not None and hasattr(storage, "list_events"):
            try:
                persona_id = self.get_active_persona_id()
                events = storage.list_events(
                    persona_id=persona_id,
                    event_type=event_type,
                    limit=max(1, min(limit, 1000)),
                )
                return [_json_safe(event) for event in events]
            except Exception as exc:
                logger.debug("Storage list_events() failed; trying repo list_events(): %s", exc)

        fn = getattr(self._repo, "list_events", None)
        if callable(fn):
            try:
                persona_id = self.get_active_persona_id()
                events = fn(
                    persona_id=persona_id,
                    event_type=event_type,
                    limit=max(1, min(limit, 1000)),
                )
                return [_json_safe(event) for event in events]
            except Exception as exc:
                logger.debug("Repo list_events() failed: %s", exc)
                return []

        return []

    def list_plugins(self) -> list[dict[str, Any]]:
        manager = getattr(self._repo, "_plugins", None)
        if manager is None:
            return []
        discover = getattr(manager, "discover", None)
        if not callable(discover):
            return []

        active = getattr(manager, "_active", {}) or {}
        result: list[dict[str, Any]] = []
        try:
            for meta in discover():
                plugin_id = str(getattr(meta, "id", ""))
                if not plugin_id:
                    continue
                result.append(
                    {
                        "id": plugin_id,
                        "name": str(getattr(meta, "name", plugin_id)),
                        "version": str(getattr(meta, "version", "unknown")),
                        "description": str(getattr(meta, "description", "")),
                        "active": plugin_id in active,
                    }
                )
        except Exception as exc:
            logger.debug("Plugin discovery failed: %s", exc)
            return []

        result.sort(key=lambda item: item["id"])
        return result

    def plugin_status(self, plugin_id: str) -> dict[str, Any]:
        manager = getattr(self._repo, "_plugins", None)
        if manager is None:
            return {"id": plugin_id, "active": False, "error": "Plugin manager unavailable"}
        status = getattr(manager, "status", None)
        if callable(status):
            try:
                return _json_safe(status(plugin_id))
            except Exception as exc:
                return {"id": plugin_id, "active": False, "error": str(exc)}
        return {"id": plugin_id, "active": False, "error": "Status API unavailable"}

    def activate_plugin(self, plugin_id: str, config: dict[str, Any] | None = None) -> bool:
        manager = getattr(self._repo, "_plugins", None)
        activate = getattr(manager, "activate", None) if manager is not None else None
        if not callable(activate):
            return False
        try:
            activate(plugin_id, config or {})
            return True
        except Exception as exc:
            logger.debug("Plugin activation failed for %s: %s", plugin_id, exc)
            return False

    def deactivate_plugin(self, plugin_id: str) -> bool:
        manager = getattr(self._repo, "_plugins", None)
        deactivate = getattr(manager, "deactivate", None) if manager is not None else None
        if not callable(deactivate):
            return False
        try:
            deactivate(plugin_id)
            return True
        except Exception as exc:
            logger.debug("Plugin deactivation failed for %s: %s", plugin_id, exc)
            return False

    @property
    def chronos_version(self) -> str:
        status = self._get_repo_status()
        version = getattr(status, "version", None) if status is not None else None
        if version:
            return str(version)
        return CHRONOS_VERSION

    def repo_dir(self) -> Path | None:
        status = self._get_repo_status()
        if status is not None:
            path_value = getattr(status, "path", None)
            if path_value:
                return Path(str(path_value))

        storage = getattr(self._repo, "_storage", None)
        db_path = getattr(storage, "db_path", None) if storage is not None else None
        if db_path:
            return Path(str(db_path)).parent

        fallback_db = getattr(self._repo, "_db_path", None)
        if fallback_db:
            return Path(str(fallback_db)).parent
        return None

    def repo_name(self) -> str | None:
        name = getattr(self._repo, "name", None)
        if isinstance(name, str) and name:
            return name
        status = self._get_repo_status()
        status_name = getattr(status, "name", None) if status is not None else None
        if isinstance(status_name, str) and status_name:
            return status_name
        repo_dir = self.repo_dir()
        return repo_dir.name if repo_dir is not None else None

    def repo_base_dir(self) -> Path | None:
        repo_dir = self.repo_dir()
        if repo_dir is None:
            return None
        return repo_dir.parent

    @staticmethod
    def _ensure_milestones_table(conn: sqlite3.Connection) -> None:
        conn.execute(
            """
            CREATE TABLE IF NOT EXISTS milestones (
                id BLOB PRIMARY KEY,
                name TEXT NOT NULL UNIQUE,
                checkpoint_id BLOB NOT NULL,
                message TEXT DEFAULT '',
                created_at INTEGER NOT NULL
            )
            """
        )
        conn.commit()

    def _resolve_checkpoint_ref(self, conn: sqlite3.Connection, ref: str) -> sqlite3.Row:
        if ref == "HEAD":
            row = conn.execute(
                "SELECT id, message, created_at FROM checkpoints ORDER BY created_at DESC LIMIT 1"
            ).fetchone()
            if row is None:
                raise ValueError("No checkpoints found")
            return row

        if ref.startswith("HEAD~"):
            try:
                offset = int(ref[5:])
            except Exception as exc:
                raise ValueError(f"Invalid ref: {ref}") from exc
            row = conn.execute(
                """
                SELECT id, message, created_at
                FROM checkpoints
                ORDER BY created_at DESC
                LIMIT 1 OFFSET ?
                """,
                (max(0, offset),),
            ).fetchone()
            if row is None:
                raise ValueError(f"Cannot resolve ref: {ref}")
            return row

        self._ensure_milestones_table(conn)
        milestone = conn.execute(
            """
            SELECT c.id, c.message, c.created_at
            FROM milestones m
            JOIN checkpoints c ON c.id = m.checkpoint_id
            WHERE m.name = ?
            """,
            (ref,),
        ).fetchone()
        if milestone is not None:
            return milestone

        rows = conn.execute(
            "SELECT id, message, created_at FROM checkpoints WHERE hex(id) LIKE ? || '%'",
            (ref.upper(),),
        ).fetchall()
        if len(rows) == 1:
            return rows[0]
        if len(rows) > 1:
            raise ValueError(f"Ambiguous checkpoint ref: {ref}")
        raise ValueError(f"Unknown checkpoint ref: {ref}")

    def _get_repo_status(self) -> Any | None:
        try:
            return getattr(self._repo, "status", None)
        except Exception as exc:
            logger.debug("Unable to read repo status: %s", exc)
            return None


def _json_safe(value: Any):
    if isinstance(value, (bytes, bytearray)):
        return value.hex()
    if isinstance(value, dict):
        return {str(k): _json_safe(v) for k, v in value.items()}
    if isinstance(value, list):
        return [_json_safe(v) for v in value]
    return value


def _memory_to_dict(memory: Any) -> dict[str, Any]:
    memory_id = getattr(memory, "id", None)
    if isinstance(memory_id, (bytes, bytearray)):
        memory_id = memory_id.hex()
    return {
        "id": str(memory_id) if memory_id is not None else None,
        "content": str(getattr(memory, "content", "")),
        "source": str(getattr(memory, "source", "")),
        "importance": float(getattr(memory, "importance", 0.0)),
        "created_at": int(getattr(memory, "created_at", 0)),
    }
