from __future__ import annotations

import pytest

import vibe.core.scratchpad as scratchpad_mod
from vibe.core.scratchpad import init_scratchpad
from vibe.core.tools.base import BaseToolState, ToolPermission
from vibe.core.tools.builtins.bash import (
    Bash,
    BashArgs,
    BashToolConfig,
    _collect_outside_dirs,
)
from vibe.core.tools.builtins.read import Read, ReadArgs, ReadConfig, ReadState
from vibe.core.tools.builtins.write_file import (
    WriteFile,
    WriteFileArgs,
    WriteFileConfig,
)
from vibe.core.tools.permissions import PermissionContext, PermissionScope


@pytest.fixture(autouse=True)
def _setup_scratchpad():
    init_scratchpad("test-session")


class TestFileToolScratchpadPermissions:
    def test_write_file_scratchpad_always_allowed(self):
        sp = scratchpad_mod.get_scratchpad_dir("test-session")
        assert sp is not None
        tool = WriteFile(config_getter=lambda: WriteFileConfig(), state=BaseToolState())
        result = tool.resolve_permission(
            WriteFileArgs(path=str(sp / "draft.py"), content="x")
        )
        assert isinstance(result, PermissionContext)
        assert result.permission is ToolPermission.ALWAYS

    def test_read_scratchpad_always_allowed(self):
        sp = scratchpad_mod.get_scratchpad_dir("test-session")
        assert sp is not None
        tool = Read(config_getter=lambda: ReadConfig(), state=ReadState())
        result = tool.resolve_permission(ReadArgs(file_path=str(sp / "notes.txt")))
        assert isinstance(result, PermissionContext)
        assert result.permission is ToolPermission.ALWAYS

    def test_scratchpad_env_file_still_allowed(self):
        """Scratchpad bypasses sensitive pattern checks."""
        sp = scratchpad_mod.get_scratchpad_dir("test-session")
        assert sp is not None
        tool = WriteFile(config_getter=lambda: WriteFileConfig(), state=BaseToolState())
        result = tool.resolve_permission(
            WriteFileArgs(path=str(sp / ".env"), content="SECRET=x")
        )
        assert isinstance(result, PermissionContext)
        assert result.permission is ToolPermission.ALWAYS

    def test_non_scratchpad_outside_dir_still_asks(self):
        tool = WriteFile(config_getter=lambda: WriteFileConfig(), state=BaseToolState())
        result = tool.resolve_permission(
            WriteFileArgs(path="/tmp/not-scratchpad/file.txt", content="x")
        )
        assert isinstance(result, PermissionContext)
        assert result.permission is ToolPermission.ASK


class TestBashScratchpadPermissions:
    def test_scratchpad_path_not_flagged_as_outside_dir(self):
        sp = scratchpad_mod.get_scratchpad_dir("test-session")
        assert sp is not None
        dirs = _collect_outside_dirs([f"cat {sp}/file.txt"])
        assert len(dirs) == 0

    def test_non_scratchpad_outside_path_still_flagged(self):
        dirs = _collect_outside_dirs(["cat /etc/hosts"])
        assert len(dirs) >= 1

    def test_bash_scratchpad_mkdir_no_outside_dir_permission(self):
        sp = scratchpad_mod.get_scratchpad_dir("test-session")
        assert sp is not None
        bash = Bash(config_getter=lambda: BashToolConfig(), state=BaseToolState())
        result = bash.resolve_permission(BashArgs(command=f"mkdir {sp}/subdir"))
        assert isinstance(result, PermissionContext)
        outside = [
            rp
            for rp in result.required_permissions
            if rp.scope is PermissionScope.OUTSIDE_DIRECTORY
        ]
        assert len(outside) == 0
