"""Memory namespaces (Mem0-style scopes) for search and future writes.

Default behavior matches historical Mugi: all hub, shards, summaries, archives
under the workspace count as ``user_durable``. ``mesh_safe`` limits reads to
``memory/mesh_safe/*.md`` so operators can store peer-shareable blurbs separately.
"""
from __future__ import annotations

import os
import re
from typing import Final

SCOPE_USER_DURABLE: Final = "user_durable"
SCOPE_MESH_SAFE: Final = "mesh_safe"

VALID_SCOPES: Final[frozenset[str]] = frozenset({SCOPE_USER_DURABLE, SCOPE_MESH_SAFE})

_MESH_THREAD_RE = re.compile(r"^(?:mesh[-_]|mesh\.|peer[-_]|group[-_]|btw_)", re.IGNORECASE)


def normalize_memory_scope(raw: str | None, *, default: str = SCOPE_USER_DURABLE) -> str:
    s = (raw or "").strip().lower()
    if not s:
        return default
    if s not in VALID_SCOPES:
        return default
    return s


def suggested_scope_for_thread_id(thread_id: str | None) -> str:
    """Hint for call-sites: mesh-like threads should prefer ``mesh_safe`` reads."""
    tid = (thread_id or "").strip()
    if not tid:
        return SCOPE_USER_DURABLE
    if _MESH_THREAD_RE.search(tid):
        return SCOPE_MESH_SAFE
    return SCOPE_USER_DURABLE


def list_mesh_safe_memory_files(workspace: str) -> list[tuple[str, str]]:
    """Return ``(rel_path, abs_path)`` for ``memory/mesh_safe/*.md``."""
    base = os.path.join(workspace, "memory", "mesh_safe")
    if not os.path.isdir(base):
        return []
    out: list[tuple[str, str]] = []
    try:
        for name in sorted(f for f in os.listdir(base) if f.endswith(".md")):
            abs_p = os.path.join(base, name)
            if os.path.isfile(abs_p):
                rel = f"memory/mesh_safe/{name}"
                out.append((rel, abs_p))
    except OSError:
        return []
    return out
