"""
Model node implementation for ML inference operations.

This module provides the ModelNode class which represents AI model inference
nodes in the pipeline. It handles model loading, hardware allocation, and
inference configuration for various NPU dongles.

Main Components:
    - ModelNode: Core model inference node implementation
    - Model configuration and validation
    - Hardware dongle management

Usage:
    from cluster4npu_ui.core.nodes.model_node import ModelNode
    
    node = ModelNode()
    node.set_property('model_path', '/path/to/model.onnx')
    node.set_property('dongle_series', '720')
"""

from .base_node import BaseNodeWithProperties


class ModelNode(BaseNodeWithProperties):
    """
    Model node for ML inference operations.
    
    This node represents an AI model inference stage in the pipeline, handling
    model loading, hardware allocation, and inference configuration.
    """
    
    __identifier__ = 'com.cluster.model_node'
    NODE_NAME = 'Model Node'
    
    def __init__(self):
        super().__init__()
        
        # Setup node connections
        self.add_input('input', multi_input=False, color=(255, 140, 0))
        self.add_output('output', color=(0, 255, 0))
        self.set_color(65, 84, 102)
        
        # Initialize properties
        self.setup_properties()
    
    def setup_properties(self):
        """Initialize model-specific properties."""
        # Model configuration
        self.create_business_property('model_path', '', {
            'type': 'file_path',
            'filter': 'Model files (*.onnx *.tflite *.pb *.nef)',
            'description': 'Path to the model file'
        })
        
        # Hardware configuration
        self.create_business_property('dongle_series', '520', [
            '520', '720', '1080', 'Custom'
        ])
        
        self.create_business_property('num_dongles', 1, {
            'min': 1,
            'max': 16,
            'description': 'Number of dongles to use for this model'
        })
        
        self.create_business_property('port_id', '', {
            'placeholder': 'e.g., 8080 or auto',
            'description': 'Port ID for dongle communication'
        })
        
        # Performance configuration
        self.create_business_property('batch_size', 1, {
            'min': 1,
            'max': 32,
            'description': 'Inference batch size'
        })
        
        self.create_business_property('max_queue_size', 10, {
            'min': 1,
            'max': 100,
            'description': 'Maximum input queue size'
        })
        
        # Advanced options
        self.create_business_property('enable_preprocessing', True, {
            'description': 'Enable built-in preprocessing'
        })
        
        self.create_business_property('enable_postprocessing', True, {
            'description': 'Enable built-in postprocessing'
        })
    
    def validate_configuration(self) -> tuple[bool, str]:
        """
        Validate the current node configuration.
        
        Returns:
            Tuple of (is_valid, error_message)
        """
        # Check model path
        model_path = self.get_property('model_path')
        if not model_path:
            return False, "Model path is required"
        
        # Check dongle series
        dongle_series = self.get_property('dongle_series')
        if dongle_series not in ['520', '720', '1080', 'Custom']:
            return False, f"Invalid dongle series: {dongle_series}"
        
        # Check number of dongles
        num_dongles = self.get_property('num_dongles')
        if not isinstance(num_dongles, int) or num_dongles < 1:
            return False, "Number of dongles must be at least 1"
        
        return True, ""
    
    def get_inference_config(self) -> dict:
        """
        Get inference configuration for pipeline execution.
        
        Returns:
            Dictionary containing inference configuration
        """
        return {
            'node_id': self.id,
            'node_name': self.name(),
            'model_path': self.get_property('model_path'),
            'dongle_series': self.get_property('dongle_series'),
            'num_dongles': self.get_property('num_dongles'),
            'port_id': self.get_property('port_id'),
            'batch_size': self.get_property('batch_size'),
            'max_queue_size': self.get_property('max_queue_size'),
            'enable_preprocessing': self.get_property('enable_preprocessing'),
            'enable_postprocessing': self.get_property('enable_postprocessing')
        }
    
    def get_hardware_requirements(self) -> dict:
        """
        Get hardware requirements for this model node.
        
        Returns:
            Dictionary containing hardware requirements
        """
        return {
            'dongle_series': self.get_property('dongle_series'),
            'num_dongles': self.get_property('num_dongles'),
            'port_id': self.get_property('port_id'),
            'estimated_memory': self._estimate_memory_usage(),
            'estimated_power': self._estimate_power_usage()
        }
    
    def _estimate_memory_usage(self) -> float:
        """Estimate memory usage in MB."""
        # Simple estimation based on batch size and number of dongles
        base_memory = 512  # Base memory in MB
        batch_factor = self.get_property('batch_size') * 50
        dongle_factor = self.get_property('num_dongles') * 100
        
        return base_memory + batch_factor + dongle_factor
    
    def _estimate_power_usage(self) -> float:
        """Estimate power usage in Watts."""
        # Simple estimation based on dongle series and count
        dongle_series = self.get_property('dongle_series')
        num_dongles = self.get_property('num_dongles')
        
        power_per_dongle = {
            '520': 2.5,
            '720': 3.5,
            '1080': 5.0,
            'Custom': 4.0
        }
        
        return power_per_dongle.get(dongle_series, 4.0) * num_dongles