import logging
from datetime import datetime, timedelta
from typing import Dict, Any, List
from ..models.base_node import BaseNode
from ..models.execution_context import ExecutionContext
from ..models.execution_result import ExecutionResult
logger = logging.getLogger(__name__)

class WaitNode(BaseNode):
    """
    Wait node that introduces delays in workflow execution.
    
    Supports configurable delay mechanisms that pause workflow execution
    for specified durations while maintaining execution state and context.
    """
    
    def __init__(self, property_id: str, node_id: str, name: str, config: Dict[str, Any], database_logger=None):
        """
        Initialize wait node.
        
        Args:
            property_id: Property identifier for this node instance
            node_id: Unique identifier for this node instance
            name: Human-readable name for the node
            config: Node configuration containing delay settings
            database_logger: Optional database logger for node-level logging
        """
        super().__init__(property_id, node_id, name, config, database_logger)
        self.node_type = "wait"

    def execute(self, context: ExecutionContext) -> ExecutionResult:
        try:
            start_time = datetime.utcnow()
            if not context.data["user_pseudo_ids"]:
                logger.error(f"No audience in node {self.node_id}")
                result = ExecutionResult.error_result(
                    error_message=f"No audience in node",
                    node_id=self.node_id
                )
                result.set_execution_time(start_time)
                return result
            
            # Get delay configuration
            duration = self.get_config_value("duration")
            time_unit = self.get_config_value("unit", "minutes")
            
            if duration is None:
                return ExecutionResult.error_result(
                    "Duration is required for wait node",
                    node_id=self.node_id
                )

            delay_seconds = self._convert_to_seconds(duration, time_unit)
            if delay_seconds <= 0:
                return ExecutionResult.error_result(
                    f"Invalid delay duration: {duration} {time_unit}",
                    node_id=self.node_id
                )
            
            end_time = start_time + timedelta(seconds=delay_seconds)
            end_time = end_time.replace(second=0, microsecond=0)
            
            wait_state = {
                "node_id": self.node_id,
                "start_time": start_time.isoformat(),
                "end_time": end_time.isoformat(),
                "duration_seconds": delay_seconds,
                "time_unit": time_unit,
                "original_duration": duration
            }
            context.set_data("wait_state", wait_state)

            #Set log result
            log_result = []
            user_pseudo_ids_success = []
            for user in context.data["user_pseudo_ids"]:
                data =  {
                            "status": 'completed',
                            "message": f'Wait until {end_time}',
                            "user_pseudo_id": user,
                            "start_time": start_time.isoformat(),
                            "end_time": end_time.isoformat(),
                            "duration_seconds": delay_seconds,
                            "time_unit": time_unit,
                            "original_duration": duration
                        }
                log_result.append(data)
            
            # Create success result
            result = ExecutionResult.success_result(
                data={
                    f"{self.node_id}": {
                        "user_pseudo_ids": user_pseudo_ids_success,
                        "log_result": log_result,
                        "wait_calcualted": end_time.isoformat()
                    }
                },
                node_id=self.node_id
            )
            result.set_execution_time(start_time)
            
            logger.info(f"Wait time completed successfully: {result}")
            return result
        except Exception as e:
            logging.error(e)

            
    def validate_config(self) -> bool:
        """
        Validate the wait node's configuration.
        
        Returns:
            True if configuration is valid, False otherwise
        """
        # Check required configuration keys
        duration = self.get_config_value("duration")
        if duration is None:
            return False
        
        # Validate duration is a positive number
        try:
            duration_num = float(duration)
            if duration_num <= 0:
                return False
        except (ValueError, TypeError):
            return False
        
        # Validate time unit if provided
        time_unit = self.get_config_value("time_unit", "minutes")
        valid_units = ["minutes", "hours", "days"]
        if time_unit not in valid_units:
            return False
        
        return True
    
    def get_required_config_keys(self) -> List[str]:
        """
        Get list of required configuration keys for wait node.
        
        Returns:
            List of required configuration keys
        """
        return ["duration"]
    
    def _convert_to_seconds(self, duration: float, time_unit: str) -> float:
        """
        Convert duration to seconds based on time unit.
        
        Args:
            duration: Duration value
            time_unit: Time unit (seconds, minutes, hours, days)
            
        Returns:
            Duration in seconds
        """
        conversion_factors = {
            "seconds": 1,
            "minutes": 60,
            "hours": 3600,
            "days": 86400
        }
        
        factor = conversion_factors.get(time_unit, 1)
        return float(duration) * factor