"""Interface for {{ module_name }} instrument.

This module provides the hardware interface for communicating with
the {{ module_name }} instrument. The interface includes measurement,
calibration, and data acquisition capabilities.

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

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

import logging
import time
from typing import Any, Optional

from {{ module_name }}_types import (
    {{ module_name | pascal_case }}CalibrationData,
    {{ module_name | pascal_case }}InterfaceConfig,
    {{ module_name | pascal_case }}Reading,
)

logger = logging.getLogger(__name__)


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

    This class encapsulates all hardware communication logic, including
    connection management, measurement, and calibration.

    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()
        >>> reading = interface.measure()
        >>> 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
        self._calibration = {{ module_name | pascal_case }}CalibrationData()

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

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

    @property
    def is_calibrated(self) -> bool:
        """Check if the instrument is calibrated."""
        return self._calibration.calibrated

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

        Raises:
            ConnectionError: If connection fails after retries.
        """
        # TODO: Implement actual connection logic
        logger.info("Connecting to {{ module_name }} instrument...")
        self._connected = True
        logger.info("Connected to {{ module_name }} instrument")

    def disconnect(self) -> None:
        """Close connection to the instrument."""
        if self._connected:
            logger.info("Disconnecting from {{ module_name }} instrument...")
            self._connected = False
            self._initialized = False
            logger.info("Disconnected from {{ module_name }} instrument")

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

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

        # TODO: Implement actual instrument initialization
        logger.info("Initializing {{ module_name }} instrument...")
        self._initialized = True
        logger.info("{{ module_name | pascal_case }} instrument initialized")

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

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

        # TODO: Implement actual shutdown logic
        logger.info("Shutting down {{ module_name }} instrument...")
        self._initialized = False
        logger.info("{{ module_name | pascal_case }} instrument shut down")

    def calibrate(self, **kwargs: Any) -> {{ module_name | pascal_case }}CalibrationData:
        """Calibrate the instrument.

        Args:
            **kwargs: Calibration parameters specific to the instrument.

        Returns:
            CalibrationData with calibration results.

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

        # TODO: Implement actual calibration logic
        logger.info("Calibrating {{ module_name }} instrument...")
        self._calibration = {{ module_name | pascal_case }}CalibrationData(
            calibrated=True,
            calibration_timestamp=time.time(),
            calibration_parameters=kwargs,
        )
        logger.info("{{ module_name | pascal_case }} instrument calibrated")
        return self._calibration

    def measure(self, channel: Optional[str] = None) -> {{ module_name | pascal_case }}Reading:
        """Take a measurement reading from the instrument.

        Args:
            channel: Optional channel or sensor to read from.

        Returns:
            Reading with the measured value.

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

        # TODO: Implement actual measurement logic
        logger.info("Taking measurement from {{ module_name }} instrument...")
        reading = {{ module_name | pascal_case }}Reading(
            value=0.0,
            units="counts",
            timestamp=time.time(),
            channel=channel,
        )
        return reading

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

        Returns:
            dict: Instrument status information.

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

        return {
            "connected": self._connected,
            "initialized": self._initialized,
            "calibrated": self._calibration.calibrated,
            "status_code": 0,
        }
