"""子进程环境隔离 — Issue #237 Phase 4

清除 IDE/编辑器注入的环境变量，防止干扰 index1 子进程。

根因 (#237 RC1): Claude Code 注入 CLAUDECODE 环境变量到子进程，
claude CLI 检测到嵌套环境后 100% 拒绝执行，导致 Observer 最强
provider 永远不可用。

设计参考: VS Code extension host blocklist 模式（env-isolation-research.md）。

使用场景:
- observer/claude.py: Claude CLI subprocess
- hooks.py: maintenance subprocess
"""

from __future__ import annotations

import os
import re
from collections.abc import Sequence

# 匹配需要清除的环境变量名（IDE/编辑器注入的）
_ENV_BLOCKLIST_PATTERNS: tuple[re.Pattern, ...] = (
    re.compile(r"^CLAUDE"),       # CLAUDECODE, CLAUDE_CODE, CLAUDE_*
    re.compile(r"^ELECTRON_"),    # Electron 框架变量
    re.compile(r"^VSCODE_"),      # VS Code 扩展变量
)

# 即使匹配 blocklist 也必须保留的变量
_ENV_PRESERVE: frozenset[str] = frozenset({
    "CLAUDE_PROJECT_DIR",     # collection 推断需要（#136）
})


def make_clean_env(
    *,
    extra_vars: dict[str, str] | None = None,
    preserve: Sequence[str] = (),
) -> dict[str, str]:
    """创建干净的子进程环境。

    从当前 os.environ 复制，移除匹配 blocklist 的变量，
    保留 _ENV_PRESERVE 和 caller 指定的 preserve 列表。

    Args:
        extra_vars: 额外添加到环境的变量（如 INDEX1_HOOK_CHILD=1）
        preserve: 调用方要求保留的额外变量名

    Returns:
        过滤后的环境变量字典

    Escape hatch:
        设置 INDEX1_ENV_PRESERVE="VAR1,VAR2" 可在不改代码的情况下
        保留特定变量。
    """
    # 用户 escape hatch
    user_preserve_raw = os.environ.get("INDEX1_ENV_PRESERVE", "")
    user_keep = frozenset(
        v.strip() for v in user_preserve_raw.split(",") if v.strip()
    )

    keep = _ENV_PRESERVE | frozenset(preserve) | user_keep

    env: dict[str, str] = {}
    for key, value in os.environ.items():
        if key in keep:
            env[key] = value
            continue
        if any(pat.match(key) for pat in _ENV_BLOCKLIST_PATTERNS):
            continue
        env[key] = value

    if extra_vars:
        env.update(extra_vars)
    return env
