import logging
import re
from typing import Any

from app.core.workflow.nodes.assigner.config import AssignerNodeConfig
from app.core.workflow.nodes.base_node import BaseNode, WorkflowState
from app.core.workflow.nodes.enums import AssignmentOperator
from app.core.workflow.nodes.operators import AssignmentOperatorInstance, AssignmentOperatorResolver
from app.core.workflow.variable_pool import VariablePool

logger = logging.getLogger(__name__)


class AssignerNode(BaseNode):
    def __init__(self, node_config: dict[str, Any], workflow_config: dict[str, Any]):
        super().__init__(node_config, workflow_config)
        self.typed_config = AssignerNodeConfig(**self.config)

    async def execute(self, state: WorkflowState) -> Any:
        """
        Execute the assignment operation defined by this node.

        Args:
            state: The current workflow state, including conversation variables,
                   node outputs, and system variables.

        Returns:
            None or the result of the assignment operation.
        """
        # Initialize a variable pool for accessing conversation, node, and system variables
        logger.info(f"节点 {self.node_id} 开始执行")
        pool = VariablePool(state)
        for assignment in self.typed_config.assignments:
            # Get the target variable selector (e.g., "conv.test")
            variable_selector = assignment.variable_selector
            if isinstance(variable_selector, str):
                # Support dot-separated string paths, e.g., "conv.test" -> ["conv", "test"]
                pattern = r"\{\{\s*(.*?)\s*\}\}"
                expression = re.sub(pattern, r"\1", variable_selector).strip()
                variable_selector = expression.split('.')

            # Only conversation variables ('conv') are allowed
            if variable_selector[0] != 'conv' and variable_selector[0] not in state["cycle_nodes"]:
                raise ValueError("Only conversation or cycle variables can be assigned.")

            # Get the value or expression to assign
            value = assignment.value
            pattern = r"\{\{\s*(.*?)\s*\}\}"
            if isinstance(value, str):
                expression = re.match(pattern, value)
                if expression:
                    expression = expression.group(1)
                    expression = re.sub(pattern, r"\1", expression).strip()
                    value = self.get_variable(expression, state)

            # Select the appropriate assignment operator instance based on the target variable type
            operator: AssignmentOperatorInstance = AssignmentOperatorResolver.resolve_by_value(
                pool.get(variable_selector)
            )(
                pool, variable_selector, value
            )

            # Execute the configured assignment operation
            match assignment.operation:
                case AssignmentOperator.COVER:
                    operator.assign()
                case AssignmentOperator.ASSIGN:
                    operator.assign()
                case AssignmentOperator.CLEAR:
                    operator.clear()
                case AssignmentOperator.ADD:
                    operator.add()
                case AssignmentOperator.SUBTRACT:
                    operator.subtract()
                case AssignmentOperator.MULTIPLY:
                    operator.multiply()
                case AssignmentOperator.DIVIDE:
                    operator.divide()
                case AssignmentOperator.APPEND:
                    operator.append()
                case AssignmentOperator.REMOVE_FIRST:
                    operator.remove_first()
                case AssignmentOperator.REMOVE_LAST:
                    operator.remove_last()
                case _:
                    raise ValueError(f"Invalid Operator: {assignment.operation}")
            logger.info(f"Node {self.node_id}: execution completed")

