"""
Shared test fixtures for sofiia-supervisor.

Uses httpx.MockTransport to mock gateway responses — no real network calls.
"""

import asyncio
import json
import sys
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional
from unittest.mock import AsyncMock, MagicMock

import pytest

# ─── Path bootstrap ───────────────────────────────────────────────────────────
_svc_root = Path(__file__).parent.parent
sys.path.insert(0, str(_svc_root))


# ─── Gateway mock helpers ─────────────────────────────────────────────────────

class MockGatewayClient:
    """
    Drop-in replacement for GatewayClient that intercepts call_tool and returns
    pre-configured responses without making HTTP requests.

    Usage:
        mock_gw = MockGatewayClient()
        mock_gw.register("job_orchestrator_tool", "start_task", {"job_id": "j_001", "status": "running"})
        mock_gw.register("job_orchestrator_tool", "get_job", {"status": "succeeded", "result": {...}})
    """

    def __init__(self):
        self._responses: Dict[str, List[Any]] = {}   # key: "tool:action" → list of responses
        self.calls: List[Dict] = []                  # recorded calls (no payload)

    def register(self, tool: str, action: str, data: Any, *, error: Optional[str] = None, retryable: bool = False):
        """Register a response for (tool, action). Multiple registrations → FIFO queue."""
        key = f"{tool}:{action}"
        self._responses.setdefault(key, []).append({
            "data": data, "error": error, "retryable": retryable
        })

    def _pop(self, tool: str, action: str) -> Dict:
        key = f"{tool}:{action}"
        queue = self._responses.get(key, [])
        if queue:
            resp = queue.pop(0)
            if not queue:
                # Keep last response for further calls
                self._responses[key] = [resp]
            return resp
        return {"data": {}, "error": None, "retryable": False}

    async def __aenter__(self):
        return self

    async def __aexit__(self, *args):
        pass

    async def call_tool(
        self,
        tool: str,
        action: str,
        params: Optional[Dict] = None,
        agent_id: str = "",
        workspace_id: str = "",
        user_id: str = "",
        graph_run_id: str = "",
        graph_node: str = "",
        **kwargs,
    ):
        # Record call metadata (no payload logged)
        self.calls.append({
            "tool": tool,
            "action": action,
            "graph_run_id": graph_run_id,
            "graph_node": graph_node,
            "agent_id": agent_id,
        })

        resp = self._pop(tool, action)
        from app.gateway_client import ToolCallResult
        if resp["error"]:
            return ToolCallResult(
                success=False,
                error_code="mock_error",
                error_message=resp["error"],
                retryable=resp.get("retryable", False),
            )
        return ToolCallResult(success=True, data=resp["data"])


# ─── Fixtures ────────────────────────────────────────────────────────────────

@pytest.fixture
def mock_gw_factory():
    """Factory: returns a MockGatewayClient and patches app.gateway_client.GatewayClient."""
    def _make(patch_target: str = "app.gateway_client.GatewayClient"):
        return MockGatewayClient()
    return _make


@pytest.fixture
def in_memory_backend():
    from app.state_backend import MemoryStateBackend
    return MemoryStateBackend()


def _run(coro):
    return asyncio.run(coro)
