"""Fake interface for {{ module_name }} robot arm.

This module provides a simulated interface for testing without hardware.
It implements the same methods as the real interface but operates entirely
in memory, with configurable latency and full state tracking for testing.

Generated by: madsci new module --template module/robot_arm
Template version: {{ template_version }}
"""

import logging
import time
from typing import Any, Optional

from {{ module_name }}_types import {{ module_name | pascal_case }}InterfaceConfig

logger = logging.getLogger(__name__)


class {{ module_name | pascal_case }}FakeInterface:
    """Fake interface for testing {{ module_name }} without hardware.

    This class simulates robot arm behavior including full lifecycle management
    (connect, initialize, shutdown, disconnect) and arm operations (home, pick,
    place, move). It is designed for:
    - Development without physical hardware
    - Automated testing in CI/CD
    - Demo and training purposes
    - Debugging workflow logic

    Example:
        >>> interface = {{ module_name | pascal_case }}FakeInterface(simulated_latency=0.01)
        >>> interface.connect()
        >>> interface.initialize()
        >>> interface.home()
        >>> result = interface.pick("sample_station")
        >>> result = interface.place("analysis_station")
        >>> status = interface.get_status()
        >>> interface.shutdown()
        >>> interface.disconnect()
    """

    def __init__(
        self,
        config: Optional[{{ module_name | pascal_case }}InterfaceConfig] = None,
        simulated_latency: float = 0.1,
        **kwargs: Any,
    ) -> None:
        """Initialize the fake interface.

        Args:
            config: Interface configuration. Uses defaults if None.
            simulated_latency: Simulated operation time in seconds.
            **kwargs: Additional configuration (ignored in fake mode).
        """
        self._config = config or {{ module_name | pascal_case }}InterfaceConfig(**kwargs)
        self._simulated_latency = simulated_latency
        self._connected = False
        self._initialized = False
        self._homed = False
        self._holding_item = False
        self._position: dict[str, float] = {"x": 0.0, "y": 0.0, "z": 0.0}
        self._operation_count = 0
        self._state: dict[str, Any] = {}
        self._movement_history: list[dict[str, Any]] = []

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

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

    @property
    def is_homed(self) -> bool:
        """Check if the robot arm has been homed."""
        return self._homed

    @property
    def operation_count(self) -> int:
        """Get the number of operations performed."""
        return self._operation_count

    @property
    def movement_history(self) -> list[dict[str, Any]]:
        """Get the history of movement operations."""
        return list(self._movement_history)

    def connect(self) -> None:
        """Simulate establishing connection to the robot arm."""
        logger.info("[FAKE] Connecting to simulated {{ module_name }} robot arm...")
        time.sleep(self._simulated_latency)
        self._connected = True
        self._state["connected_at"] = time.time()
        logger.info("[FAKE] Connected to simulated {{ module_name }} robot arm")

    def disconnect(self) -> None:
        """Simulate closing connection to the robot arm."""
        if self._connected:
            logger.info("[FAKE] Disconnecting from simulated {{ module_name }} robot arm...")
            self._connected = False
            self._initialized = False
            self._homed = False
            self._state["disconnected_at"] = time.time()
            logger.info("[FAKE] Disconnected from simulated {{ module_name }} robot arm")

    def initialize(self) -> None:
        """Simulate robot arm initialization.

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

        logger.info("[FAKE] Initializing simulated {{ module_name }} robot arm...")
        time.sleep(self._simulated_latency)
        self._initialized = True
        self._state["initialized_at"] = time.time()
        logger.info("[FAKE] Simulated {{ module_name }} robot arm initialized")

    def shutdown(self) -> None:
        """Simulate robot arm shutdown.

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

        logger.info("[FAKE] Shutting down simulated {{ module_name }} robot arm...")
        time.sleep(self._simulated_latency)
        self._initialized = False
        self._homed = False
        self._state["shutdown_at"] = time.time()
        logger.info("[FAKE] Simulated {{ module_name }} robot arm shut down")

    def home(self) -> None:
        """Simulate homing the robot arm.

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

        logger.info("[FAKE] Homing simulated {{ module_name }} robot arm...")
        time.sleep(self._simulated_latency)
        self._homed = True
        self._position = {"x": 0.0, "y": 0.0, "z": 0.0}
        self._operation_count += 1
        self._state["last_operation"] = "home"
        self._state["last_operation_time"] = time.time()

        self._movement_history.append(
            {
                "operation": "home",
                "position": dict(self._position),
                "operation_number": self._operation_count,
                "timestamp": time.time(),
            }
        )

        logger.info("[FAKE] Simulated {{ module_name }} robot arm homed")

    def pick(self, location: str, **kwargs: Any) -> dict:
        """Simulate picking up an item from a named location.

        Args:
            location: Name of the location to pick from.
            **kwargs: Additional parameters for the pick operation.

        Returns:
            dict: Result of the pick operation.

        Raises:
            RuntimeError: If not connected, not initialized, or not homed.
        """
        if not self._connected:
            raise RuntimeError("Not connected. Call connect() first.")
        if not self._initialized:
            raise RuntimeError("Robot arm not initialized. Call initialize() first.")
        if not self._homed:
            raise RuntimeError("Robot arm not homed. Call home() first.")

        time.sleep(self._simulated_latency)

        self._operation_count += 1
        self._holding_item = True
        self._state["last_operation"] = "pick"
        self._state["last_operation_time"] = time.time()
        self._state["last_location"] = location

        self._movement_history.append(
            {
                "operation": "pick",
                "location": location,
                "parameters": kwargs,
                "operation_number": self._operation_count,
                "timestamp": time.time(),
            }
        )

        logger.info(f"[FAKE] Simulated pick from location: {location}")
        return {
            "action": "pick",
            "location": location,
            "parameters": kwargs,
            "success": True,
            "operation_number": self._operation_count,
        }

    def place(self, location: str, **kwargs: Any) -> dict:
        """Simulate placing an item at a named location.

        Args:
            location: Name of the location to place at.
            **kwargs: Additional parameters for the place operation.

        Returns:
            dict: Result of the place operation.

        Raises:
            RuntimeError: If not connected, not initialized, or not homed.
        """
        if not self._connected:
            raise RuntimeError("Not connected. Call connect() first.")
        if not self._initialized:
            raise RuntimeError("Robot arm not initialized. Call initialize() first.")
        if not self._homed:
            raise RuntimeError("Robot arm not homed. Call home() first.")

        time.sleep(self._simulated_latency)

        self._operation_count += 1
        self._holding_item = False
        self._state["last_operation"] = "place"
        self._state["last_operation_time"] = time.time()
        self._state["last_location"] = location

        self._movement_history.append(
            {
                "operation": "place",
                "location": location,
                "parameters": kwargs,
                "operation_number": self._operation_count,
                "timestamp": time.time(),
            }
        )

        logger.info(f"[FAKE] Simulated place at location: {location}")
        return {
            "action": "place",
            "location": location,
            "parameters": kwargs,
            "success": True,
            "operation_number": self._operation_count,
        }

    def move(self, x: float, y: float, z: float, speed: Optional[float] = None) -> dict:
        """Simulate moving the arm to a specific position.

        Args:
            x: Target X coordinate in mm.
            y: Target Y coordinate in mm.
            z: Target Z coordinate in mm.
            speed: Movement speed in mm/s (optional).

        Returns:
            dict: Result of the move operation including final position.

        Raises:
            RuntimeError: If not connected, not initialized, or not homed.
        """
        if not self._connected:
            raise RuntimeError("Not connected. Call connect() first.")
        if not self._initialized:
            raise RuntimeError("Robot arm not initialized. Call initialize() first.")
        if not self._homed:
            raise RuntimeError("Robot arm not homed. Call home() first.")

        time.sleep(self._simulated_latency)

        self._operation_count += 1
        self._position = {"x": x, "y": y, "z": z}
        self._state["last_operation"] = "move"
        self._state["last_operation_time"] = time.time()

        self._movement_history.append(
            {
                "operation": "move",
                "position": {"x": x, "y": y, "z": z},
                "speed": speed,
                "operation_number": self._operation_count,
                "timestamp": time.time(),
            }
        )

        logger.info(f"[FAKE] Simulated move to ({x}, {y}, {z})")
        return {
            "action": "move",
            "position": {"x": x, "y": y, "z": z},
            "speed": speed,
            "success": True,
            "operation_number": self._operation_count,
        }

    def get_position(self) -> dict:
        """Get the current simulated position of the robot arm.

        Returns:
            dict: Current position with x, y, z coordinates.

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

        return dict(self._position)

    def get_status(self) -> dict:
        """Get the simulated robot arm status.

        Returns:
            dict: Simulated robot arm status information.

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

        return {
            "connected": self._connected,
            "initialized": self._initialized,
            "homed": self._homed,
            "holding_item": self._holding_item,
            "position": dict(self._position),
            "operation_count": self._operation_count,
            "last_operation": self._state.get("last_operation"),
        }

    def get_state(self) -> dict[str, Any]:
        """Get the current internal state (useful for testing).

        Returns:
            Dictionary of internal state including connection status,
            initialization status, homing status, operation count,
            and movement history.
        """
        return {
            "connected": self._connected,
            "initialized": self._initialized,
            "homed": self._homed,
            "holding_item": self._holding_item,
            "position": dict(self._position),
            "operation_count": self._operation_count,
            "movement_history_length": len(self._movement_history),
            **self._state,
        }

    def reset_state(self) -> None:
        """Reset internal state (useful for testing).

        Clears operation count, movement history, and internal state
        while preserving connection, initialization, and homing status.
        """
        self._operation_count = 0
        self._movement_history = []
        self._state = {}
