"""Interface for {{ module_name }} device.

This module provides the hardware interface for communicating with
the {{ module_name }} device. The interface includes full device lifecycle
management: connect, initialize, shutdown, disconnect, and status reporting.

The interface is independent of MADSci and can be used directly in
notebooks or scripts.

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

import logging
from typing import Any, Optional

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

logger = logging.getLogger(__name__)


class {{ module_name | pascal_case }}Interface:
    """Interface for communicating with the {{ module_name }} device.

    This class encapsulates all hardware communication logic, including
    device lifecycle management (connect, initialize, shutdown, disconnect)
    and command execution.

    It can be used independently of MADSci in notebooks or scripts.

    Example:
        >>> config = {{ module_name | pascal_case }}InterfaceConfig()
        >>> interface = {{ module_name | pascal_case }}Interface(config=config)
        >>> interface.connect()
        >>> interface.initialize()
        >>> result = interface.execute_command("run_protocol", param1="value1")
        >>> status = interface.get_status()
        >>> interface.shutdown()
        >>> interface.disconnect()
    """

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

        Args:
            config: Interface configuration. Uses defaults if None.
            **kwargs: Additional configuration options.
        """
        self._config = config or {{ module_name | pascal_case }}InterfaceConfig(**kwargs)
        self._connected = False
        self._initialized = False

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

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

    def connect(self) -> None:
        """Establish connection to the device.

        This method opens the communication channel to the device
        (e.g., serial port, TCP/IP socket, vendor SDK connection).

        Raises:
            ConnectionError: If connection fails after retries.
        """
        # TODO: Implement actual connection logic
        # Example:
        # for attempt in range(self._config.retry_count):
        #     try:
        #         self._connection = DeviceDriver.connect(
        #             timeout=self._config.connection_timeout
        #         )
        #         break
        #     except ConnectionError:
        #         if attempt == self._config.retry_count - 1:
        #             raise

        logger.info("Connecting to {{ module_name }} device...")
        self._connected = True
        logger.info("Connected to {{ module_name }} device")

    def disconnect(self) -> None:
        """Close connection to the device.

        This method safely closes the communication channel. It should
        be called after shutdown() to ensure the device is in a safe state.
        """
        if self._connected:
            # TODO: Implement actual disconnection logic
            # Example:
            # self._connection.close()

            logger.info("Disconnecting from {{ module_name }} device...")
            self._connected = False
            self._initialized = False
            logger.info("Disconnected from {{ module_name }} device")

    def initialize(self) -> None:
        """Initialize the device for operation.

        This method performs device-specific initialization such as
        homing, calibration, self-test, or loading configuration.
        Must be called after connect() and before executing commands.

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

        # TODO: Implement actual device initialization
        # Example:
        # self._connection.home()
        # self._connection.calibrate()
        # self._connection.load_config()

        logger.info("Initializing {{ module_name }} device...")
        self._initialized = True
        logger.info("{{ module_name | pascal_case }} device initialized")

    def shutdown(self) -> None:
        """Safely shut down the device.

        This method puts the device into a safe state before disconnecting.
        It may include parking mechanisms, saving calibration data,
        or releasing locked resources.

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

        # TODO: Implement actual shutdown logic
        # Example:
        # self._connection.park()
        # self._connection.save_calibration()
        # self._connection.release_resources()

        logger.info("Shutting down {{ module_name }} device...")
        self._initialized = False
        logger.info("{{ module_name | pascal_case }} device shut down")

    def get_status(self) -> dict:
        """Get the current status of the device.

        Returns:
            dict: Device status information including connection state,
                initialization state, and device-specific status data.

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

        # TODO: Implement actual status retrieval
        # Example:
        # hw_status = self._connection.get_status()
        # return {
        #     "connected": self._connected,
        #     "initialized": self._initialized,
        #     "status_code": hw_status.code,
        #     "temperature": hw_status.temperature,
        #     "position": hw_status.position,
        # }

        logger.info("Getting {{ module_name }} device status")
        return {
            "connected": self._connected,
            "initialized": self._initialized,
            "status_code": 0,
        }

    def execute_command(self, command: str, **kwargs: Any) -> dict:
        """Execute a command on the device.

        Args:
            command: The command string to execute on the device.
            **kwargs: Additional parameters for the command.

        Returns:
            dict: Command execution result with status and any output data.

        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.")

        # TODO: Implement actual command execution
        # Example:
        # response = self._connection.send_command(command, **kwargs)
        # return {
        #     "command": command,
        #     "success": response.success,
        #     "data": response.data,
        # }

        logger.info(f"Executing command on {{ module_name }}: {command}")
        return {
            "command": command,
            "parameters": kwargs,
            "success": True,
        }
