"""Mock interface for {{ module_name }}.

This module provides a mock-based interface using unittest.mock for
fine-grained control in unit tests. Unlike the fake interface (which
simulates realistic behavior), this mock interface lets you:

- Assert specific method calls were made
- Control return values per-call
- Raise exceptions on demand
- Verify call order and arguments

Generated by: madsci new interface --type mock
Template version: {{ template_version }}
"""

import logging
from typing import Any, Optional
from unittest.mock import MagicMock

logger = logging.getLogger(__name__)


class {{ module_name | pascal_case }}MockInterface:
    """Mock interface for {{ module_name }} unit testing.

    This class wraps unittest.mock.MagicMock to provide a mock interface
    that tracks all method calls for assertion in tests.

    Unlike the fake interface (which simulates realistic device behavior),
    this mock interface is designed for unit testing where you need to:
    - Verify exact method calls and arguments
    - Control return values for specific test scenarios
    - Simulate error conditions by configuring side_effect

    Example:
        >>> interface = {{ module_name | pascal_case }}MockInterface()
        >>> interface.connect()
        >>> interface.mock.connect.assert_called_once()
        >>>
        >>> # Configure custom return value
        >>> interface.set_return_value("get_status", {"status": "error"})
        >>> status = interface.get_status()
        >>> assert status == {"status": "error"}
        >>>
        >>> # Simulate errors
        >>> interface.set_side_effect("connect", ConnectionError("Timeout"))
    """

    def __init__(self, **kwargs: Any) -> None:
        """Initialize the mock interface.

        Args:
            **kwargs: Configuration options (stored but not used).
        """
        self._mock = MagicMock()
        self._connected = False
        self._initialized = False
        self._config = kwargs

    @property
    def mock(self) -> MagicMock:
        """Access the underlying MagicMock for assertions."""
        return self._mock

    @property
    def is_connected(self) -> bool:
        """Check if the interface is connected."""
        return self._connected

    @property
    def is_initialized(self) -> bool:
        """Check if the device has been initialized."""
        return self._initialized

    def set_return_value(self, method_name: str, return_value: Any) -> None:
        """Configure the return value for a mocked method.

        Args:
            method_name: Name of the method to configure.
            return_value: Value to return when the method is called.
        """
        getattr(self._mock, method_name).return_value = return_value

    def set_side_effect(
        self, method_name: str, side_effect: Any
    ) -> None:
        """Configure a side effect for a mocked method.

        Args:
            method_name: Name of the method to configure.
            side_effect: Exception or callable to use as side effect.
        """
        getattr(self._mock, method_name).side_effect = side_effect

    def connect(self) -> None:
        """Mock connection to the device."""
        self._mock.connect()
        self._connected = True

    def disconnect(self) -> None:
        """Mock disconnection from the device."""
        if self._connected:
            self._mock.disconnect()
            self._connected = False
            self._initialized = False

    def initialize(self) -> None:
        """Mock device initialization.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._connected:
            raise RuntimeError("Not connected to device. Call connect() first.")
        self._mock.initialize()
        self._initialized = True

    def shutdown(self) -> None:
        """Mock device shutdown.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._connected:
            raise RuntimeError("Not connected to device. Call connect() first.")
        self._mock.shutdown()
        self._initialized = False

    def execute_command(self, command: str, **kwargs: Any) -> dict:
        """Mock command execution.

        Args:
            command: The command to execute.
            **kwargs: Additional command parameters.

        Returns:
            dict: Configured return value, or default success dict.

        Raises:
            RuntimeError: If not connected or not initialized.
        """
        if not self._connected:
            raise RuntimeError("Not connected to device. Call connect() first.")
        if not self._initialized:
            raise RuntimeError("Device not initialized. Call initialize() first.")

        result = self._mock.execute_command(command, **kwargs)
        if isinstance(result, MagicMock):
            return {"command": command, "parameters": kwargs, "success": True}
        return result

    def get_status(self) -> dict:
        """Mock status retrieval.

        Returns:
            dict: Configured return value, or default status dict.

        Raises:
            RuntimeError: If not connected.
        """
        if not self._connected:
            raise RuntimeError("Not connected to device. Call connect() first.")

        result = self._mock.get_status()
        if isinstance(result, MagicMock):
            return {
                "connected": self._connected,
                "initialized": self._initialized,
                "status_code": 0,
            }
        return result

    def reset_mock(self) -> None:
        """Reset the mock, clearing all call history and configured behaviors."""
        self._mock.reset_mock()
        self._connected = False
        self._initialized = False

    def get_call_count(self, method_name: Optional[str] = None) -> int:
        """Get the number of times a method was called.

        Args:
            method_name: Specific method to check. If None, returns total calls.

        Returns:
            int: Number of calls.
        """
        if method_name:
            return getattr(self._mock, method_name).call_count
        return self._mock.call_count
