"""
Debug and Monitoring nodes.
"""

from typing import Any, Dict
from ybagent.node import BaseNode, NodeType, NodeInput, NodeOutput
import json
import time

class LoggerNode(BaseNode):
    """
    Node for logging data during execution.
    """
    
    def __init__(self, id: str, level: str = "INFO", **config):
        config.update({
            "level": level
        })
        config.pop('node_type', None)
        super().__init__(id=id, node_type=NodeType.LOGGER, **config)
    
    def _define_inputs_outputs(self):
        self.metadata.inputs = [
            NodeInput(name="data", type="any", required=True, description="Data to log"),
            NodeInput(name="message", type="str", required=False, description="Log message prefix")
        ]
        self.metadata.outputs = [
            NodeOutput(name="data", type="any", description="Pass-through data")
        ]
    
    def execute(self, inputs: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
        data = inputs.get("data")
        message = inputs.get("message", "")
        level = self.metadata.config.get("level", "INFO")
        
        log_entry = f"[{level}] Node {self.metadata.id}: {message} {data}"
        print(log_entry)
        
        # In a real app, this would connect to the WorkflowLogger
        # context.get("logger").log(level, message, data)
        
        return {"data": data}


class DebugNode(BaseNode):
    """
    Node for debugging (inspecting values).
    """
    
    def __init__(self, id: str, **config):
        config.pop('node_type', None)
        super().__init__(id=id, node_type=NodeType.DEBUG, **config)
    
    def _define_inputs_outputs(self):
        self.metadata.inputs = [
            NodeInput(name="input", type="any", required=True, description="Value to inspect")
        ]
        self.metadata.outputs = [
            NodeOutput(name="output", type="any", description="Pass-through value")
        ]
    
    def execute(self, inputs: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
        val = inputs.get("input")
        print(f"\n--- DEBUG NODE {self.metadata.id} ---")
        print(f"Type: {type(val)}")
        print(f"Value: {val}")
        print("----------------------------------\n")
        return {"output": val}


class NotificationNode(BaseNode):
    """
    Node that sends notifications (console, email, webhook).
    """
    
    def __init__(self, id: str, **config):
        super().__init__(id, NodeType.NOTIFICATION, **config)
    
    def _define_inputs_outputs(self):
        self.metadata.inputs.append(
            NodeInput(name="message", type="string", description="Message to send")
        )
        self.metadata.inputs.append(
            NodeInput(name="recipient", type="string", required=False, description="Email address or Webhook URL")
        )
        self.metadata.outputs.append(
            NodeOutput(name="status", type="string", description="Notification status")
        )
    
    def execute(self, inputs: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
        message = inputs.get("message")
        recipient = inputs.get("recipient")
        channel = self.metadata.config.get("channel", "console")  # console, email, webhook
        
        if channel == "console":
            print(f"\n[NOTIFICATION] {message}\n")
            return {"status": "sent_to_console"}
            
        elif channel == "email":
            # In a real app, use SMTP or an email service
            print(f"\n[EMAIL to {recipient}] {message}\n")
            return {"status": "sent_to_email"}
            
        elif channel == "webhook":
            # In a real app, make an HTTP POST
            print(f"\n[WEBHOOK to {recipient}] {message}\n")
            return {"status": "sent_to_webhook"}
            
        return {"status": "unknown_channel"}


class FailNode(BaseNode):
    """
    Node that fails a specified number of times before succeeding.
    Useful for testing retry logic.
    """
    
    def __init__(self, id: str, **config):
        super().__init__(id, NodeType.FAIL, **config)
        self.attempts = 0
    
    def _define_inputs_outputs(self):
        self.metadata.inputs.append(
            NodeInput(name="input", type="any", description="Input to pass through")
        )
        self.metadata.outputs.append(
            NodeOutput(name="output", type="any", description="Passed input")
        )
    
    def execute(self, inputs: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
        fail_count = int(self.metadata.config.get("fail_count", 1))
        self.attempts += 1
        
        print(f"[FailNode] Attempt {self.attempts}/{fail_count + 1}")
        
        if self.attempts <= fail_count:
            raise ValueError(f"Simulated failure (Attempt {self.attempts})")
        
        return {"output": inputs.get("input")}
