#!/usr/bin/env python3
"""
REPEAT Executor
Company: eXonware.com
Author: eXonware Backend Team
Email: connect@exonware.com
Version: 0.9.0.6
"""

from typing import Any, Optional
from ..base import AUniversalOperationExecutor
from ....contracts import QueryAction, ExecutionContext, ExecutionResult
from ....defs import OperationType
from ..utils import extract_items, extract_field_value


class RepeatExecutor(AUniversalOperationExecutor):
    """REPEAT - Gremlin repeat step."""
    OPERATION_NAME = "REPEAT"
    OPERATION_TYPE = OperationType.GRAPH
    SUPPORTED_NODE_TYPES = []

    def _do_execute(self, action: QueryAction, context: ExecutionContext) -> ExecutionResult:
        params = action.params
        result_data = self._execute_repeat(context.node, params, context)
        return ExecutionResult(
            success=True,
            data=result_data,
            action_type=self.OPERATION_NAME,
            metadata={"operation": self.OPERATION_NAME},
        )

    def _matches_condition(self, items: list[Any], condition: Optional[dict]) -> bool:
        if not condition:
            return False
        for item in items:
            if not isinstance(item, dict):
                continue
            if all(item.get(k) == v for k, v in condition.items()):
                return True
        return False

    def _execute_repeat(self, node: Any, params: dict, context: ExecutionContext) -> dict:
        action = params.get("action")
        times = params.get("times")
        until_condition = params.get("until_condition")
        emit = bool(params.get("emit", False))
        engine = context.metadata.get("engine") if isinstance(context.metadata, dict) else None

        current_data = node
        emissions = []
        iterations = 0
        max_iterations = int(times) if times is not None else 100

        while iterations < max_iterations:
            iterations += 1
            if engine is not None and action is not None:
                if isinstance(action, QueryAction):
                    step_action = action
                elif isinstance(action, dict):
                    step_action = QueryAction(type=action.get("type", ""), params=action.get("params", {}))
                else:
                    step_action = QueryAction(type=str(action), params={})
                step_context = ExecutionContext(
                    node=current_data,
                    variables=dict(context.variables),
                    options=dict(context.options),
                    parent_context=context,
                    metadata=dict(context.metadata),
                    engine_type=context.engine_type,
                )
                step_result = engine.execute_tree(step_action, step_context)
                if not step_result.success:
                    break
                current_data = step_result.data
            if emit:
                emissions.extend(extract_items(current_data))
            if self._matches_condition(extract_items(current_data), until_condition):
                break
            if times is None and not until_condition:
                break

        final_items = emissions if emit else extract_items(current_data)
        return {
            "items": final_items,
            "count": len(final_items),
            "iterations": iterations,
            "emit": emit,
        }
