"""Sandbox 容器管理(DESIGN §7.5)。

模块边界:
- `network.py`:Docker network ensure(`zcbot-sandbox-net`,`--internal` 隔离 outbound + cross-container)
- `pool.py`:per-user 容器生命周期(ensure / mark_active / reap_idle / shutdown_all)
- `__init__.py`:module-level singleton(`init_pool` / `get_pool`),给 web lifespan 与
  `agent_builder` 共享同一个池实例。

不在本目录:`shell` / `run_python` 工具的 docker exec 调用 ── 那是 `core/executor_docker.py`,
调用本模块的 `pool.ensure(user_id)` 拿到容器名后再 exec。
"""
from __future__ import annotations

from pathlib import Path
from typing import Optional

from .pool import SandboxPool, container_name, setup_pool
from .network import NETWORK_NAME, ensure_network


__all__ = [
    "SandboxPool",
    "container_name",
    "setup_pool",
    "NETWORK_NAME",
    "ensure_network",
    "init_pool",
    "get_pool",
]


# Module-level singleton。web lifespan 启动钩子调 `init_pool(user_root_base)`,
# `agent_builder` 在构造 DockerExecutor 时 `get_pool()` 拿同一实例。
# 未初始化 → `get_pool()` 返 None,agent_builder 此时必须不走 docker 分支。
_pool: Optional[SandboxPool] = None


def init_pool(
    user_root_base: Path,
    repo_root: Optional[Path] = None,
    sandbox_cfg: Optional[dict] = None,
) -> SandboxPool:
    """幂等初始化 module-level pool。返回 pool 实例。

    lifespan 调一次;ensure_network 内部也幂等。重复调用返回同一实例(不重新建)。
    `repo_root` 给 fs 工具进容器后 SKILL references 的 ro mount(详 pool.py)。
    `sandbox_cfg` 是 agent.yaml 的 `sandbox` 段,含 memory/cpus/pids_limit。
    """
    global _pool
    if _pool is None:
        _pool = setup_pool(user_root_base, repo_root=repo_root, sandbox_cfg=sandbox_cfg)
    return _pool


def get_pool() -> Optional[SandboxPool]:
    return _pool
