"""Block executor for handling nested block execution.

This module provides the BlockExecutor class which is injected into composite
executors (conditional, switch, loop) to execute their nested blocks. It wraps
the ExecutionPipeline, allowing nested steps to flow through the same pipeline
stages as top-level steps.

Architecture:
    ExecutorRegistry creates BlockExecutor(pipeline) and injects it into
    composite executors. This breaks the circular dependency that would
    otherwise exist if executors directly referenced the pipeline or registry.
"""

from agent_flows.core.flow_engine.pipeline import ExecutionPipeline
from agent_flows.models.execution import ExecutionContext, ExecutorResult
from agent_flows.models.flow import FlowStep
from agent_flows.utils.logging import get_logger

logger = get_logger(__name__)


class BlockExecutor:
    """Executes nested blocks through the execution pipeline.

    Injected into composite executors by ExecutorRegistry. Provides a clean
    interface for running nested steps without exposing the full pipeline
    or creating circular dependencies.
    """

    def __init__(self, pipeline: ExecutionPipeline) -> None:
        """Initialize block executor.

        Args:
            pipeline: The execution pipeline that nested blocks will traverse.
        """
        self._pipeline = pipeline

    async def execute(self, block: FlowStep, context: ExecutionContext) -> ExecutorResult:
        """Execute a nested block through the full pipeline.

        The block traverses all pipeline stages (interpolation, credential
        resolution, execution, tracing, etc.) just like a top-level step.

        Args:
            block: The nested block (step) to execute
            context: Current execution context with variables and credentials

        Returns:
            ExecutorResult from the block's execution
        """
        logger.debug(
            "Executing nested block",
            extra={
                "block_type": block.type,
                "block_id": block.id,
            },
        )
        return await self._pipeline.execute(block, context)
