# src/agentsh_secure_sandbox/testing/mock.py
from __future__ import annotations

from typing import Any

from ..core.types import (
    ExecResult,
    ReadFileFailure,
    ReadFileSuccess,
    SecuredSandbox,
    SecurityMode,
    WriteFileFailure,
    WriteFileSuccess,
    SandboxAdapter,
)


def mock_secured_sandbox(
    *,
    commands: dict[str, ExecResult] | None = None,
    files: dict[str, str] | None = None,
    security_mode: SecurityMode = "full",
    session_id: str = "mock-session",
) -> SecuredSandbox:
    """
    Create a mock SecuredSandbox for unit testing.

    Args:
        commands: Map of command string -> ExecResult.
        files: Map of path -> content (mutable).
        security_mode: Reported security mode.
        session_id: Reported session ID.
    """
    file_store = dict(files or {})
    cmd_store = commands or {}

    class _Mock:
        @property
        def session_id(self) -> str:
            return session_id

        @property
        def security_mode(self) -> SecurityMode:
            return security_mode

        async def exec(
            self,
            command: str,
            *,
            cwd: str | None = None,
            timeout: float | None = None,
        ) -> ExecResult:
            if command in cmd_store:
                return cmd_store[command]
            return ExecResult(stdout="", stderr=f'mock: no response for "{command}"', exit_code=1)

        async def write_file(
            self, path: str, content: str | bytes
        ) -> WriteFileSuccess | WriteFileFailure:
            if isinstance(content, bytes):
                file_store[path] = content.decode("utf-8", errors="replace")
            else:
                file_store[path] = content
            return WriteFileSuccess(success=True, path=path)

        async def read_file(self, path: str) -> ReadFileSuccess | ReadFileFailure:
            if path in file_store:
                return ReadFileSuccess(success=True, path=path, content=file_store[path])
            return ReadFileFailure(success=False, path=path, error=f'mock: file not found "{path}"')

        async def stop(self) -> None:
            pass

    return _Mock()


def mock_adapter(
    *,
    exec_results: list[ExecResult] | None = None,
) -> SandboxAdapter:
    """
    Create a mock SandboxAdapter for testing provisioning.
    Returns exec results in sequence.
    """
    results = list(exec_results or [])
    call_idx = 0

    class _MockAdapter:
        async def exec(
            self,
            cmd: str,
            args: list[str] | None = None,
            opts: Any = None,
        ) -> ExecResult:
            nonlocal call_idx
            if call_idx < len(results):
                r = results[call_idx]
                call_idx += 1
                return r
            return ExecResult(stdout="", stderr="", exit_code=0)

        async def write_file(self, path: str, content: str | bytes, *, sudo: bool = False) -> None:
            pass

        async def read_file(self, path: str) -> str:
            return ""

        async def stop(self) -> None:
            pass

        async def file_exists(self, path: str) -> bool:
            return False

    return _MockAdapter()
