"""
BIBIVIDI — Sandbox tests

Tests the OS-level isolation layer (resource limits + seccomp on Linux).
Sandbox is best-effort: failures are logged but don't crash the runner.
"""
import sys

import pytest

from bvd.engine.library import Script
from bvd.engine.runner import run_script
from bvd.engine.sandbox import get_preexec_fn


def _make_script(code: str) -> Script:
    return Script(id="sandbox-test", name="Test", description="test", code=code)


# ── preexec_fn availability ────────────────────────────────────────────────────

def test_get_preexec_fn_returns_none_on_windows(monkeypatch):
    monkeypatch.setattr(sys, "platform", "win32")
    # Re-import to pick up the monkeypatched platform value
    import importlib

    import bvd.engine.sandbox as sbx
    importlib.reload(sbx)
    assert sbx.get_preexec_fn() is None
    importlib.reload(sbx)   # restore


@pytest.mark.skipif(sys.platform == "win32", reason="preexec_fn is POSIX-only")
def test_get_preexec_fn_returns_callable_on_posix():
    fn = get_preexec_fn()
    assert callable(fn)


# ── Sandbox enforcement via runner ────────────────────────────────────────────
# These run the actual subprocess with the sandbox applied.

@pytest.mark.skipif(sys.platform == "win32", reason="resource limits are POSIX-only")
@pytest.mark.asyncio
async def test_sandbox_blocks_fork():
    """RLIMIT_NPROC=0 prevents scripts from spawning child processes."""
    # multiprocessing.Process uses fork internally
    s = _make_script(
        "import multiprocessing\n"
        "p = multiprocessing.Process(target=lambda: None)\n"
        "p.start()\n"
        "print('should not reach here')"
    )
    result = await run_script(s, "test")
    # Script should fail (exit_code != 0) or fall back to original prompt
    assert result.output != "should not reach here"


@pytest.mark.skipif(sys.platform == "win32", reason="resource limits are POSIX-only")
@pytest.mark.asyncio
async def test_sandbox_blocks_file_write():
    """RLIMIT_FSIZE=0 prevents scripts from writing files."""
    import os
    import tempfile
    tmp = tempfile.mktemp(suffix=".txt")
    s = _make_script(
        f"open('{tmp}', 'w').write('evil')\n"
        "print('wrote file')"
    )
    await run_script(s, "test")
    # RLIMIT_FSIZE=0: open() may create an empty file but write() is blocked.
    # The script must not have successfully written content.
    content = open(tmp).read() if os.path.exists(tmp) else ""
    assert content == "", "sandbox should have blocked file write"
    if os.path.exists(tmp):
        os.unlink(tmp)


@pytest.mark.skipif(sys.platform != "linux", reason="seccomp is Linux-only")
@pytest.mark.asyncio
async def test_sandbox_blocks_network_on_linux():
    """Seccomp BPF blocks socket() — no network connections from scripts."""
    s = _make_script(
        "import socket\n"
        "s = socket.socket()\n"   # socket() syscall — blocked by seccomp
        "print('socket created')"
    )
    result = await run_script(s, "test")
    assert "socket created" not in result.output


@pytest.mark.skipif(sys.platform != "linux", reason="seccomp is Linux-only")
@pytest.mark.asyncio
async def test_sandbox_blocks_exec_on_linux():
    """Seccomp BPF blocks execve() — scripts cannot spawn external programs."""
    s = _make_script(
        "import subprocess\n"
        "subprocess.run(['echo', 'hi'])\n"
        "print('exec ran')"
    )
    result = await run_script(s, "test")
    assert "exec ran" not in result.output


@pytest.mark.asyncio
async def test_sandbox_does_not_break_normal_scripts():
    """Legitimate sandboxed scripts still run correctly with isolation active."""
    s = _make_script(
        "import json, re, math\n"
        "data = json.loads('{\"x\": 42}')\n"
        "print(f'result: {math.sqrt(data[\"x\"]):.2f}')"
    )
    result = await run_script(s, "test")
    assert "result: 6.48" in result.output
    assert result.exit_code == 0
