"""环境隔离测试 — Issue #237 Phase 4"""

import os

import pytest

from index1.env_utils import (
    _ENV_BLOCKLIST_PATTERNS,
    _ENV_PRESERVE,
    make_clean_env,
)


class TestMakeCleanEnv:
    def test_removes_claudecode(self, monkeypatch):
        """CLAUDECODE 被清除（RC1 根因）"""
        monkeypatch.setenv("CLAUDECODE", "1")
        env = make_clean_env()
        assert "CLAUDECODE" not in env

    def test_removes_claude_code(self, monkeypatch):
        """CLAUDE_CODE 变体被清除"""
        monkeypatch.setenv("CLAUDE_CODE", "1")
        env = make_clean_env()
        assert "CLAUDE_CODE" not in env

    def test_removes_claude_star(self, monkeypatch):
        """所有 CLAUDE_* 变量被清除"""
        monkeypatch.setenv("CLAUDE_SESSION_ID", "abc")
        monkeypatch.setenv("CLAUDE_MODEL", "sonnet")
        env = make_clean_env()
        assert "CLAUDE_SESSION_ID" not in env
        assert "CLAUDE_MODEL" not in env

    def test_preserves_claude_project_dir(self, monkeypatch):
        """CLAUDE_PROJECT_DIR 被保留（collection 推断需要）"""
        monkeypatch.setenv("CLAUDE_PROJECT_DIR", "/my/project")
        env = make_clean_env()
        assert env.get("CLAUDE_PROJECT_DIR") == "/my/project"

    def test_removes_electron(self, monkeypatch):
        """ELECTRON_* 变量被清除"""
        monkeypatch.setenv("ELECTRON_RUN_AS_NODE", "1")
        env = make_clean_env()
        assert "ELECTRON_RUN_AS_NODE" not in env

    def test_removes_vscode(self, monkeypatch):
        """VSCODE_* 变量被清除"""
        monkeypatch.setenv("VSCODE_PID", "12345")
        env = make_clean_env()
        assert "VSCODE_PID" not in env

    def test_keeps_normal_vars(self, monkeypatch):
        """正常变量保留（PATH, HOME 等）"""
        monkeypatch.setenv("PATH", "/usr/bin")
        monkeypatch.setenv("HOME", "/home/user")
        env = make_clean_env()
        assert "PATH" in env
        assert "HOME" in env

    def test_extra_vars_added(self, monkeypatch):
        """extra_vars 被添加到环境"""
        env = make_clean_env(extra_vars={"INDEX1_HOOK_CHILD": "1"})
        assert env.get("INDEX1_HOOK_CHILD") == "1"

    def test_extra_vars_override(self, monkeypatch):
        """extra_vars 覆盖同名环境变量"""
        monkeypatch.setenv("MY_VAR", "old")
        env = make_clean_env(extra_vars={"MY_VAR": "new"})
        assert env["MY_VAR"] == "new"

    def test_preserve_parameter(self, monkeypatch):
        """preserve 参数指定的变量不被清除"""
        monkeypatch.setenv("CLAUDE_CUSTOM", "keep_me")
        env = make_clean_env(preserve=["CLAUDE_CUSTOM"])
        assert env.get("CLAUDE_CUSTOM") == "keep_me"

    def test_user_escape_hatch(self, monkeypatch):
        """INDEX1_ENV_PRESERVE 环境变量作为 escape hatch"""
        monkeypatch.setenv("CLAUDE_SPECIAL", "important")
        monkeypatch.setenv("INDEX1_ENV_PRESERVE", "CLAUDE_SPECIAL")
        env = make_clean_env()
        assert env.get("CLAUDE_SPECIAL") == "important"

    def test_user_escape_hatch_multiple(self, monkeypatch):
        """INDEX1_ENV_PRESERVE 支持逗号分隔多个变量"""
        monkeypatch.setenv("CLAUDE_A", "1")
        monkeypatch.setenv("CLAUDE_B", "2")
        monkeypatch.setenv("INDEX1_ENV_PRESERVE", "CLAUDE_A,CLAUDE_B")
        env = make_clean_env()
        assert env.get("CLAUDE_A") == "1"
        assert env.get("CLAUDE_B") == "2"

    def test_user_escape_hatch_empty(self, monkeypatch):
        """INDEX1_ENV_PRESERVE 为空时无影响"""
        monkeypatch.setenv("CLAUDECODE", "1")
        monkeypatch.setenv("INDEX1_ENV_PRESERVE", "")
        env = make_clean_env()
        assert "CLAUDECODE" not in env

    def test_no_blocklist_vars_in_output(self, monkeypatch):
        """综合检查：所有 blocklist 变量都不在输出中"""
        monkeypatch.setenv("CLAUDECODE", "1")
        monkeypatch.setenv("CLAUDE_SESSION", "x")
        monkeypatch.setenv("ELECTRON_INIT", "1")
        monkeypatch.setenv("VSCODE_CWD", "/tmp")
        monkeypatch.setenv("SAFE_VAR", "ok")

        env = make_clean_env()
        assert "CLAUDECODE" not in env
        assert "CLAUDE_SESSION" not in env
        assert "ELECTRON_INIT" not in env
        assert "VSCODE_CWD" not in env
        assert env.get("SAFE_VAR") == "ok"


class TestBlocklistPatterns:
    def test_patterns_compile(self):
        """所有 pattern 都是有效的正则表达式"""
        for pat in _ENV_BLOCKLIST_PATTERNS:
            assert hasattr(pat, "match")

    def test_preserve_set(self):
        """CLAUDE_PROJECT_DIR 在保留列表中"""
        assert "CLAUDE_PROJECT_DIR" in _ENV_PRESERVE
