"""Pytest configuration and shared fixtures for mcp_vm_blackbox tests.

External packages that are not installed in the test environment are patched
into ``sys.modules`` at import time so that ``server.py`` can be loaded
without requiring VirtualBox, vagrant, WinRM, or the private ``mcp_servers``
and ``workstation`` packages.

The vm-blackbox-record scripts directory is also added to sys.path so that
the test modules for vm_capture and backends can import those scripts directly.
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import TYPE_CHECKING
from unittest.mock import MagicMock

import pytest

if TYPE_CHECKING:
    import types

# ---------------------------------------------------------------------------
# Ensure vm-blackbox-record scripts are importable
# ---------------------------------------------------------------------------

_SCRIPTS_DIR = Path(__file__).parent.parent.parent.parent / "skills" / "vm-blackbox-record" / "scripts"
if str(_SCRIPTS_DIR) not in sys.path:
    sys.path.insert(0, str(_SCRIPTS_DIR))

# ---------------------------------------------------------------------------
# Patch unavailable external modules before any test-module imports
# ---------------------------------------------------------------------------

_EXTERNAL_MODULES = [
    # server.py runtime deps
    "libtmux",
    "vagrant",
    "mcp_servers",
    "mcp_servers.targets",
    "mcp_servers.tunnel",
    "workstation",
    "workstation.vm_control",
    "workstation.vm_control.vbox_dispatch",
    "workstation.vm_control.winrm_client",
]

for _mod_name in _EXTERNAL_MODULES:
    sys.modules.setdefault(_mod_name, MagicMock())


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


@pytest.fixture(autouse=True)
def mock_vboxmanage_on_path() -> None:
    """No-op: VBoxManageBackend no longer uses shutil.which or subprocess.

    The backend now uses vboxapi (screenshot) and asyncssh to localhost (recording).
    Validation happens on first use; no PATH check at construction time.
    """


@pytest.fixture(scope="session")
def server_module() -> types.ModuleType:
    """Return the imported server module with all external deps mocked.

    Returns:
        The ``packages.mcp_vm_blackbox.server`` module object.
    """
    import packages.mcp_vm_blackbox.server as srv

    return srv


# ---------------------------------------------------------------------------
# Phase 2: Goal State mocks
# ---------------------------------------------------------------------------

from unittest.mock import AsyncMock  # noqa: E402


@pytest.fixture
def mock_ctx() -> MagicMock:
    """Mock FastMCP Context with Phase 2 methods."""
    ctx = MagicMock()
    ctx.elicit = AsyncMock()
    ctx.set_state = AsyncMock()
    ctx.get_state = AsyncMock(return_value=None)
    ctx.delete_state = AsyncMock()
    ctx.enable_components = AsyncMock()
    return ctx


@pytest.fixture
def mock_winrm_raw() -> tuple[MagicMock, MagicMock]:
    """Mock winrm.Session with raw result supporting std_out/std_err/status_code."""
    session = MagicMock()
    result = MagicMock()
    result.std_out = b"OPEN\n"
    result.std_err = b""
    result.status_code = 0
    session.run_ps = MagicMock(return_value=result)
    return session, result


@pytest.fixture
def mock_asyncssh_conn() -> MagicMock:
    """Mock asyncssh connection with async run support."""
    conn = MagicMock()
    run_result = MagicMock()
    run_result.stdout = "OPEN\n"
    run_result.stderr = ""
    run_result.returncode = 0
    conn.run = AsyncMock(return_value=run_result)
    return conn
