"""Unit tests for sandbox pool lifecycle and limits."""

from __future__ import annotations

import sys
from types import SimpleNamespace

import evaluation.sandbox_pool as sp


class FakeSemaphore:
    def __init__(self, acquired: bool = True) -> None:
        self.acquired = acquired
        self.released = 0

    def acquire(self, timeout: int = 0) -> bool:
        return self.acquired

    def release(self) -> None:
        self.released += 1


class FakeSandbox:
    def __init__(self, sid: str = "sb-1") -> None:
        self.id = sid
        self.closed = False
        self.killed = False

    def close(self) -> None:
        self.closed = True

    def kill(self) -> None:
        self.killed = True


def setup_function() -> None:
    sp.SandboxManager._instance = None


def test_create_without_template_id(monkeypatch) -> None:
    mgr = sp.SandboxManager()
    mgr._semaphore = FakeSemaphore(acquired=True)
    fake = FakeSandbox("sb-no-template")

    class SandboxCls:
        @staticmethod
        def create(*args, **kwargs):
            assert "timeout" in kwargs
            return fake

    monkeypatch.setitem(sys.modules, "ppio_sandbox.code_interpreter", SimpleNamespace(Sandbox=SandboxCls))
    sb = mgr.create(sandbox_timeout=10)
    assert sb is fake


def test_create_busy_raises() -> None:
    mgr = sp.SandboxManager()
    mgr._semaphore = FakeSemaphore(acquired=False)
    try:
        mgr.create(sandbox_timeout=10)
        assert False, "expected SandboxBusyError"
    except sp.SandboxBusyError:
        pass


def test_create_and_destroy_success(monkeypatch) -> None:
    mgr = sp.SandboxManager()
    mgr._semaphore = FakeSemaphore(acquired=True)
    fake = FakeSandbox("sb-ok")

    class SandboxCls:
        @staticmethod
        def create(template_id=None, timeout=0):
            assert template_id == "tpl"
            return fake

    monkeypatch.setitem(sys.modules, "ppio_sandbox.code_interpreter", SimpleNamespace(Sandbox=SandboxCls))

    sb = mgr.create(sandbox_timeout=22, template_id="tpl")
    assert sb is fake
    stats = mgr.get_stats()
    assert stats["total_created"] == 1
    assert stats["current_active"] == 1

    mgr.destroy(sb)
    stats2 = mgr.get_stats()
    assert stats2["total_destroyed"] == 1
    assert stats2["current_active"] == 0
    assert fake.closed is True


def test_helper_functions(monkeypatch) -> None:
    mgr = sp.SandboxManager()
    sp.SandboxManager._instance = mgr
    monkeypatch.setattr(
        mgr,
        "create",
        lambda sandbox_timeout, template_id=None, cpu_count=None, memory_mb=None: "sandbox",
    )
    monkeypatch.setattr(mgr, "destroy", lambda sandbox: None)
    monkeypatch.setattr(mgr, "get_stats", lambda: {"ok": 1})

    assert sp.create_sandbox(10, "tpl") == "sandbox"
    assert sp.create_sandbox(10) == "sandbox"
    sp.destroy_sandbox("sandbox")
    assert sp.get_sandbox_stats() == {"ok": 1}
