"""
Base IoT connector interface for equipment integration
"""

from abc import ABC, abstractmethod
from typing import Dict, Any, List, Optional
from datetime import datetime
from dataclasses import dataclass


@dataclass
class SensorReading:
    """Standardized sensor reading data structure"""
    timestamp: datetime
    temperature: Optional[float] = None
    temperature_zones: Optional[Dict[str, float]] = None
    target_temperature: Optional[float] = None
    humidity: Optional[float] = None
    target_humidity: Optional[float] = None
    energy_consumption_kwh: Optional[float] = None
    power_current_kw: Optional[float] = None
    operational_status: Optional[str] = None
    cycle_stage: Optional[str] = None
    cycle_progress_percentage: Optional[float] = None
    time_remaining_minutes: Optional[int] = None
    motor_speed_rpm: Optional[float] = None
    door_status: Optional[str] = None
    steam_level: Optional[float] = None
    product_weight_kg: Optional[float] = None
    moisture_content: Optional[float] = None
    additional_sensors: Optional[Dict[str, Any]] = None


@dataclass
class ConnectionStatus:
    """Connection status information"""
    is_connected: bool
    status: str  # connected, disconnected, error, unknown
    message: str
    response_time_ms: Optional[int] = None
    error_details: Optional[str] = None
    last_successful_connection: Optional[datetime] = None


@dataclass
class EquipmentCapabilities:
    """Equipment IoT capabilities"""
    supports_temperature: bool = False
    supports_humidity: bool = False
    supports_energy_monitoring: bool = False
    supports_remote_control: bool = False
    supports_realtime: bool = False
    temperature_zones: int = 1
    supported_protocols: List[str] = None
    manufacturer_specific_features: Optional[Dict[str, Any]] = None

    def __post_init__(self):
        if self.supported_protocols is None:
            self.supported_protocols = []


class BaseIoTConnector(ABC):
    """
    Base abstract class for IoT equipment connectors

    All manufacturer-specific connectors must implement this interface
    """

    def __init__(self, equipment_id: str, config: Dict[str, Any]):
        """
        Initialize the IoT connector

        Args:
            equipment_id: Unique equipment identifier
            config: Connection configuration including endpoint, credentials, etc.
        """
        self.equipment_id = equipment_id
        self.config = config
        self.endpoint = config.get('endpoint')
        self.port = config.get('port')
        self.credentials = config.get('credentials', {})
        self._is_connected = False
        self._last_error: Optional[str] = None

    @abstractmethod
    async def connect(self) -> ConnectionStatus:
        """
        Establish connection to the equipment

        Returns:
            ConnectionStatus with connection details
        """
        pass

    @abstractmethod
    async def disconnect(self) -> bool:
        """
        Close connection to the equipment

        Returns:
            True if disconnected successfully
        """
        pass

    @abstractmethod
    async def test_connection(self) -> ConnectionStatus:
        """
        Test connection without establishing persistent connection

        Returns:
            ConnectionStatus with test results
        """
        pass

    @abstractmethod
    async def get_current_reading(self) -> Optional[SensorReading]:
        """
        Get current sensor readings from the equipment

        Returns:
            SensorReading with current data or None if unavailable
        """
        pass

    @abstractmethod
    async def get_capabilities(self) -> EquipmentCapabilities:
        """
        Discover equipment capabilities

        Returns:
            EquipmentCapabilities describing what the equipment supports
        """
        pass

    @abstractmethod
    async def get_status(self) -> Dict[str, Any]:
        """
        Get equipment status information

        Returns:
            Dictionary with status details
        """
        pass

    async def set_target_temperature(self, temperature: float) -> bool:
        """
        Set target temperature (if supported)

        Args:
            temperature: Target temperature in Celsius

        Returns:
            True if command sent successfully
        """
        raise NotImplementedError("Remote control not supported by this equipment")

    async def start_cycle(self, params: Dict[str, Any]) -> bool:
        """
        Start production cycle (if supported)

        Args:
            params: Cycle parameters

        Returns:
            True if cycle started successfully
        """
        raise NotImplementedError("Remote control not supported by this equipment")

    async def stop_cycle(self) -> bool:
        """
        Stop current production cycle (if supported)

        Returns:
            True if cycle stopped successfully
        """
        raise NotImplementedError("Remote control not supported by this equipment")

    def get_protocol_name(self) -> str:
        """Get the protocol name used by this connector"""
        return self.__class__.__name__.replace('Connector', '').lower()

    def is_connected(self) -> bool:
        """Check if currently connected"""
        return self._is_connected

    def get_last_error(self) -> Optional[str]:
        """Get last error message"""
        return self._last_error

    def _set_error(self, error: str):
        """Set error message"""
        self._last_error = error

    def _clear_error(self):
        """Clear error message"""
        self._last_error = None


class ConnectorFactory:
    """
    Factory for creating appropriate IoT connectors based on protocol
    """

    _connectors: Dict[str, type] = {}

    @classmethod
    def register_connector(cls, protocol: str, connector_class: type):
        """
        Register a connector implementation

        Args:
            protocol: Protocol name (e.g., 'rest_api', 'opc_ua')
            connector_class: Connector class implementing BaseIoTConnector
        """
        cls._connectors[protocol.lower()] = connector_class

    @classmethod
    def create_connector(cls, protocol: str, equipment_id: str, config: Dict[str, Any]) -> BaseIoTConnector:
        """
        Create connector instance for specified protocol

        Args:
            protocol: Protocol name
            equipment_id: Equipment identifier
            config: Connection configuration

        Returns:
            Connector instance

        Raises:
            ValueError: If protocol not supported
        """
        connector_class = cls._connectors.get(protocol.lower())
        if not connector_class:
            raise ValueError(f"Unsupported IoT protocol: {protocol}")

        return connector_class(equipment_id, config)

    @classmethod
    def get_supported_protocols(cls) -> List[str]:
        """Get list of supported protocols"""
        return list(cls._connectors.keys())
