# Copyright (c) 2025 Patrick Motsch
# I/O node executor - delegates to ActionExecutor.

import logging
from typing import Dict, Any

logger = logging.getLogger(__name__)


class IOExecutor:
    """Execute I/O nodes by calling ActionExecutor.executeAction(method, action, params)."""

    def __init__(self, services: Any):
        self.services = services

    async def execute(
        self,
        node: Dict[str, Any],
        context: Dict[str, Any],
    ) -> Any:
        from modules.workflows.processing.core.actionExecutor import ActionExecutor

        nodeType = node.get("type", "")
        nodeId = node.get("id", "")
        logger.info("IOExecutor node %s type=%s", nodeId, nodeType)
        if not nodeType.startswith("io."):
            logger.debug("IOExecutor node %s not io.* -> None", nodeId)
            return None

        parts = nodeType.split(".", 2)
        if len(parts) < 3:
            logger.debug("IOExecutor node %s invalid type parts -> None", nodeId)
            return None
        _, methodName, actionName = parts
        logger.info("IOExecutor node %s method=%s action=%s", nodeId, methodName, actionName)

        nodeOutputs = context.get("nodeOutputs", {})
        params = dict(node.get("parameters") or {})

        from modules.workflows.automation2.graphUtils import resolveParameterReferences
        resolvedParams = resolveParameterReferences(params, nodeOutputs)
        logger.info("IOExecutor node %s resolvedParams keys=%s", nodeId, list(resolvedParams.keys()))

        inputSources = context.get("inputSources", {}).get(nodeId, {})
        if 0 in inputSources:
            srcId, _ = inputSources[0]
            inp = nodeOutputs.get(srcId)
            from modules.workflows.automation2.executors.actionNodeExecutor import _getDocumentsFromUpstream
            docs = _getDocumentsFromUpstream(inp) if isinstance(inp, dict) else []
            if docs:
                resolvedParams.setdefault("documentList", docs)
            elif inp is not None:
                resolvedParams.setdefault("input", inp)

        executor = ActionExecutor(self.services)
        logger.info("IOExecutor node %s calling executeAction(%s, %s)", nodeId, methodName, actionName)
        result = await executor.executeAction(methodName, actionName, resolvedParams)
        docs_list = [d.model_dump() if hasattr(d, "model_dump") else d for d in (result.documents or [])]
        out = {
            "success": result.success,
            "error": result.error,
            "documents": docs_list,
            "documentList": docs_list,
            "data": result.model_dump() if hasattr(result, "model_dump") else {"success": result.success, "error": result.error},
        }
        logger.info(
            "IOExecutor node %s result: success=%s error=%s doc_count=%d",
            nodeId,
            result.success,
            result.error,
            len(out.get("documents", [])),
        )
        return out
