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

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 RecursiveCteExecutor(AUniversalOperationExecutor):
    """RECURSIVE_CTE - Recursive expansion with depth guard."""
    OPERATION_NAME = "RECURSIVE_CTE"
    OPERATION_TYPE = OperationType.ADVANCED
    SUPPORTED_NODE_TYPES = []

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

    def _execute_recursive_cte(self, node: Any, params: dict, context: ExecutionContext) -> dict:
        all_items = extract_items(node)
        base_items = extract_items(params.get("base_items", []))
        recursive_field = params.get("recursive_field")
        id_field = params.get("id_field", "id")
        max_depth = int(params.get("max_depth", 100))

        if not recursive_field:
            return {"items": [], "count": 0, "error": "recursive_field is required"}

        index_by_parent: dict[Any, list[Any]] = {}
        for item in all_items:
            parent_id = extract_field_value(item, recursive_field)
            index_by_parent.setdefault(parent_id, []).append(item)

        results = list(base_items)
        frontier = list(base_items)
        seen = {extract_field_value(item, id_field) for item in base_items}
        depth = 0

        while frontier and depth < max_depth:
            next_frontier = []
            for parent in frontier:
                parent_id = extract_field_value(parent, id_field)
                for child in index_by_parent.get(parent_id, []):
                    child_id = extract_field_value(child, id_field)
                    if child_id in seen:
                        continue
                    seen.add(child_id)
                    results.append(child)
                    next_frontier.append(child)
            frontier = next_frontier
            depth += 1

        return {
            "items": results,
            "count": len(results),
            "depth_reached": depth,
            "max_depth": max_depth,
            "recursive_field": recursive_field,
            "id_field": id_field,
        }
