# -*- coding: iso-8859-1 -*-
"""
Temperature controller interface and base classes.

This module provides a consistent interface for temperature controllers
to enable pluggable temperature monitoring systems.
"""

from abc import ABC, abstractmethod

# Plugin registry for temperature controllers
_controller_registry = {}


def register_controller(name: str, controller_class):
    """
    Register a temperature controller implementation.
    
    Args:
        name: Unique identifier for this controller type
        controller_class: Class that implements TemperatureController
    """
    _controller_registry[name] = controller_class


def create_controller(name: str, *args, **kwargs):
    """
    Create a temperature controller instance by name.
    
    Args:
        name: Registered controller type name
        *args: Positional arguments to pass to controller constructor
        **kwargs: Keyword arguments to pass to controller constructor
        
    Returns:
        TemperatureController: Instance of the requested controller
        
    Raises:
        ValueError: If controller name is not registered and cannot be imported
    """
    # If not found, try to auto-import the module
    if name not in _controller_registry:
        # Map known controller names to their modules
        module_map = {
            'simulated': 'damaris.tools.temperature_simulator',
            'eurotherm': 'damaris.tools.eurotherm',
        }
        if name in module_map:
            try:
                # Import the module which will register the controller
                import importlib
                importlib.import_module(module_map[name])
            except ImportError as e:
                raise ValueError(f"Failed to import controller '{name}': {e}. Available: {list(_controller_registry.keys())}")
        
        # Check again after import
        if name not in _controller_registry:
            raise ValueError(f"Unknown temperature controller: {name}. Available: {list(_controller_registry.keys())}")
    
    return _controller_registry[name](*args, **kwargs)


def get_controller_names() -> list:
    """
    Get list of available controller names.
    
    Returns:
        list: List of registered controller type names
    """
    return list(_controller_registry.keys())


# Pre-register built-in controllers by importing their modules
# This ensures they're available without explicit imports
try:
    from . import eurotherm
except ImportError as e:
    # Eurotherm may require serial module which might not be installed
    # That's OK, it will be imported on-demand if needed
    pass

try:
    from . import temperature_simulator
except ImportError as e:
    # Simulator should always work (no external dependencies)
    # But if it fails, it will be imported on-demand
    pass


class TemperatureController(ABC):
    """
    Abstract base class for temperature controllers.
    
    All temperature controller implementations (Eurotherm, Lakeshore, etc.)
    should inherit from this class and implement the abstract methods.
    """

    @abstractmethod
    def get_temperature(self) -> float:
        """
        Read current temperature in Celsius.
        
        Returns:
            float: Current temperature in degrees Celsius.
            
        Raises:
            IOError: If communication with the device fails.
            RuntimeError: If the device is not ready or returns invalid data.
        """
        pass

    @abstractmethod
    def get_setpoint(self) -> float:
        """
        Read the target setpoint temperature in Celsius.
        
        Returns:
            float: Target temperature in degrees Celsius.
        """
        pass

    @abstractmethod
    def set_setpoint(self, temperature: float) -> bool:
        """
        Set the target temperature setpoint.
        
        Args:
            temperature: Target temperature in degrees Celsius.
            
        Returns:
            bool: True if the setpoint was successfully set, False otherwise.
        """
        pass

    def close(self):
        """
        Clean up resources (e.g., close serial connections).
        
        This method should be called when the controller is no longer needed.
        The default implementation does nothing; subclasses should override
        if they have resources to clean up.
        """
        pass
