"""
测试 SafetyGuard —— 注释行剥离、白名单、危险命令拦截
"""
import sys
import tempfile
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))

import pytest
from aacode.utils.safety import SafetyGuard


@pytest.fixture
def guard():
    with tempfile.TemporaryDirectory() as td:
        yield SafetyGuard(Path(td))


class TestCommandParsing:
    """命令解析基础测试"""

    def test_empty_command(self, guard):
        r = guard.check_command("")
        assert not r["allowed"]

    def test_whitespace_only(self, guard):
        r = guard.check_command("   ")
        assert not r["allowed"]

    def test_whitespace_with_newlines(self, guard):
        r = guard.check_command("\n\n  \n")
        assert not r["allowed"]


class TestCommentStripping:
    """注释行剥离（本次修复的核心）"""

    def test_leading_comment_line(self, guard):
        r = guard.check_command("# Install deps\npip list")
        assert r["allowed"], f"leading comment line rejected: {r['reason']}"

    def test_leading_comment_lines(self, guard):
        r = guard.check_command("# Step 1\n# Step 2\necho done")
        assert r["allowed"], f"multiple comment lines rejected: {r['reason']}"

    def test_comment_with_indent(self, guard):
        r = guard.check_command("  # comment with leading space\nls")
        assert r["allowed"], f"indented comment rejected: {r['reason']}"

    def test_only_comments(self, guard):
        r = guard.check_command("# just a comment")
        assert r["allowed"], f"only comments should be safe: {r['reason']}"
        assert r["risk_level"] == guard.RISK_SAFE

    def test_only_comments_multiline(self, guard):
        r = guard.check_command("# line 1\n# line 2\n# line 3")
        assert r["allowed"], f"only comments (multiline) should be safe: {r['reason']}"
        assert r["risk_level"] == guard.RISK_SAFE

    def test_comment_after_command(self, guard):
        r = guard.check_command("echo hello # inline comment")
        assert r["allowed"], f"inline comment rejected: {r['reason']}"

    def test_mixed_comments_and_empty(self, guard):
        r = guard.check_command("\n\n# comment\n\nls\n")
        assert r["allowed"], f"mixed comments/empty rejected: {r['reason']}"

    def test_real_world_pip_install(self, guard):
        cmd = "# Make sure pip is up to date\npip install --upgrade pip"
        r = guard.check_command(cmd)
        assert r["allowed"], f"pip with comment rejected: {r['reason']}"

    def test_real_world_brew_install(self, guard):
        cmd = "# Install required tools\nbrew install wget curl"
        r = guard.check_command(cmd)
        assert r["allowed"], f"brew with comment rejected: {r['reason']}"


class TestWhitelistCommands:
    """白名单命令测试"""

    def test_basic_ls(self, guard):
        assert guard.check_command("ls")["allowed"]

    def test_basic_echo(self, guard):
        assert guard.check_command("echo hello")["allowed"]

    def test_basic_git(self, guard):
        assert guard.check_command("git status")["allowed"]

    def test_basic_cat(self, guard):
        assert guard.check_command("cat /tmp/test.txt")["allowed"]

    def test_basic_grep(self, guard):
        assert guard.check_command("grep foo bar.txt")["allowed"]

    def test_basic_pip(self, guard):
        assert guard.check_command("pip install requests")["allowed"]

    def test_basic_npm(self, guard):
        assert guard.check_command("npm install")["allowed"]

    def test_basic_python(self, guard):
        assert guard.check_command("python3 -c 'print(1)'")["allowed"]

    def test_basic_curl(self, guard):
        assert guard.check_command("curl https://example.com")["allowed"]

    def test_macos_open(self, guard):
        assert guard.check_command("open .")["allowed"]

    def test_macos_sw_vers(self, guard):
        assert guard.check_command("sw_vers")["allowed"]

    def test_macos_defaults(self, guard):
        assert guard.check_command("defaults read com.apple.finder")["allowed"]

    def test_macos_launchctl(self, guard):
        assert guard.check_command("launchctl list")["allowed"]

    def test_macos_osascript(self, guard):
        assert guard.check_command('osascript -e "beep"')["allowed"]

    def test_macos_xcrun(self, guard):
        assert guard.check_command("xcrun --version")["allowed"]

    def test_macos_diskutil(self, guard):
        assert guard.check_command("diskutil list")["allowed"]

    def test_macos_mdfind(self, guard):
        assert guard.check_command("mdfind kMDItemFSName == 'test.py'")["allowed"]

    def test_macos_sips(self, guard):
        assert guard.check_command("sips -g all image.png")["allowed"]

    def test_macos_plutil(self, guard):
        assert guard.check_command("plutil -lint Info.plist")["allowed"]

    def test_macos_caffeinate(self, guard):
        assert guard.check_command("caffeinate -s sleep 10")["allowed"]

    def test_macos_pmset(self, guard):
        assert guard.check_command("pmset -g batt")["allowed"]

    def test_macos_hdiutil(self, guard):
        assert guard.check_command("hdiutil info")["allowed"]

    def test_macos_xattr(self, guard):
        assert guard.check_command("xattr -l file.txt")["allowed"]

    def test_macos_textutil(self, guard):
        assert guard.check_command("textutil -convert txt docx")["allowed"]

    def test_logger(self, guard):
        assert guard.check_command("logger test message")["allowed"]


class TestDangerousCommands:
    """危险命令拦截"""

    def test_reboot(self, guard):
        r = guard.check_command("reboot now")
        assert r["allowed"]  # dangerous_patterns 默认 action=log，允许但记录
        assert "logged" in r.get("reason", "").lower()

    def test_shutdown(self, guard):
        r = guard.check_command("shutdown -h now")
        assert r["allowed"]
        assert "logged" in r.get("reason", "").lower()

    def test_format(self, guard):
        r = guard.check_command("format /dev/sda")
        assert r["allowed"]
        assert "logged" in r.get("reason", "").lower()

    def test_dd(self, guard):
        r = guard.check_command("dd if=/dev/zero of=/dev/sda")
        assert r["allowed"]
        assert "logged" in r.get("reason", "").lower()

    def test_unknown_command(self, guard):
        r = guard.check_command("nonexistent_cmd_xyz")
        assert not r["allowed"]
        assert "whitelist" in r.get("reason", "").lower()

    def test_rm_root(self, guard):
        r = guard.check_command("rm -rf /")
        assert not r["allowed"]

    def test_kill(self, guard):
        r = guard.check_command("kill -9 1")
        assert r["allowed"]  # high_risk_commands 返回警告但不阻止
        assert r["risk_level"] == "warning"


class TestMultiLineCommands:
    """多行命令"""

    def test_multi_line_no_comments(self, guard):
        cmd = "echo first\necho second\necho third"
        r = guard.check_command(cmd)
        assert r["allowed"]

    def test_multi_line_with_comments(self, guard):
        cmd = "# step 1\necho first\n# step 2\necho second"
        r = guard.check_command(cmd)
        assert r["allowed"]

    def test_multi_line_dangerous_in_comment_only(self, guard):
        # 注释里的危险命令不应触发拦截
        cmd = "# rm -rf /\necho safe"
        r = guard.check_command(cmd)
        assert r["allowed"]

    def test_multi_line_mixed_comment_and_dangerous(self, guard):
        # reboot 在 dangerous_patterns 中 action=log，允许但记录
        cmd = "# do something\nreboot now"
        r = guard.check_command(cmd)
        assert r["allowed"]
        assert "logged" in r.get("reason", "").lower()


class TestPathSafety:
    """路径安全检查"""

    def test_project_path_allowed(self, guard):
        r = guard.check_command(f"touch {guard.project_root / Path('test.txt')}")
        assert r["allowed"]

    def test_tmp_path_allowed(self, guard):
        r = guard.check_command("touch /tmp/test.txt")
        assert r["allowed"]

    def test_system_path_denied(self, guard):
        r = guard.check_command("rm -rf /etc/passwd")
        assert not r["allowed"]
