"""
ExecutionResult class for standardizing node execution responses.
"""

from typing import Dict, Any, Optional
from datetime import datetime
import json


class ExecutionResult:
    """
    Standardizes the response from node execution operations.
    
    Provides consistent structure for success/failure status, data payload,
    and error handling across all node types.
    """
    
    def __init__(
        self, 
        success: bool, 
        data: Optional[Dict[str, Any]] = None, 
        error_message: Optional[str] = None,
        node_id: Optional[str] = None
    ):
        """
        Initialize execution result.
        
        Args:
            success: Whether the execution was successful
            data: Data payload from the execution
            error_message: Error message if execution failed
            node_id: ID of the node that produced this result
        """
        self.success = success
        self.data = data or {}
        self.error_message = error_message
        self.node_id = node_id
        self.timestamp = datetime.utcnow()
        self.execution_time_ms: Optional[int] = None
    
    def set_execution_time(self, start_time: datetime) -> None:
        """
        Calculate and set execution time based on start time.
        
        Args:
            start_time: When execution started
        """
        duration = self.timestamp - start_time
        self.execution_time_ms = int(duration.total_seconds() * 1000)
    
    def add_data(self, key: str, value: Any) -> None:
        """
        Add data to the result payload.
        
        Args:
            key: Data key
            value: Data value
        """
        self.data[key] = value
    
    def get_data(self, key: str, default: Any = None) -> Any:
        """
        Get data from the result payload.
        
        Args:
            key: Data key to retrieve
            default: Default value if key not found
            
        Returns:
            Data value or default
        """
        return self.data.get(key, default)
    
    def merge_data(self, data: Dict[str, Any]) -> None:
        """
        Merge additional data into the result payload.
        
        Args:
            data: Dictionary of data to merge
        """
        self.data.update(data)
    
    def to_dict(self) -> Dict[str, Any]:
        """
        Convert result to dictionary representation.
        
        Returns:
            Dictionary representation of the result
        """
        return {
            'success': self.success,
            'data': self.data,
            'error_message': self.error_message,
            'node_id': self.node_id,
            'timestamp': self.timestamp.isoformat(),
            'execution_time_ms': self.execution_time_ms
        }
    
    def to_json(self) -> str:
        """
        Serialize result to JSON string.
        
        Returns:
            JSON string representation of the result
        """
        return json.dumps(self.to_dict(), default=str)
    
    @classmethod
    def success_result(
        cls, 
        data: Optional[Dict[str, Any]] = None, 
        node_id: Optional[str] = None
    ) -> 'ExecutionResult':
        """
        Create a successful execution result.
        
        Args:
            data: Success data payload
            node_id: ID of the node that produced this result
            
        Returns:
            ExecutionResult instance indicating success
        """
        return cls(success=True, data=data, node_id=node_id)
    
    @classmethod
    def error_result(
        cls, 
        error_message: str, 
        data: Optional[Dict[str, Any]] = None,
        node_id: Optional[str] = None
    ) -> 'ExecutionResult':
        """
        Create a failed execution result.
        
        Args:
            error_message: Description of the error
            data: Any data collected before the error
            node_id: ID of the node that produced this result
            
        Returns:
            ExecutionResult instance indicating failure
        """
        return cls(success=False, data=data, error_message=error_message, node_id=node_id)
    
    def is_success(self) -> bool:
        """
        Check if the execution was successful.
        
        Returns:
            True if successful, False otherwise
        """
        return self.success
    
    def is_error(self) -> bool:
        """
        Check if the execution failed.
        
        Returns:
            True if failed, False otherwise
        """
        return not self.success
    
    def __str__(self) -> str:
        """String representation of the result."""
        status = "SUCCESS" if self.success else "ERROR"
        return f"ExecutionResult({status}, node_id={self.node_id})"
    
    def __repr__(self) -> str:
        """Detailed string representation of the result."""
        return f"ExecutionResult(success={self.success}, node_id={self.node_id}, data_keys={list(self.data.keys())})"