#!/usr/bin/env python3
"""
FLATTEN 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 FlattenExecutor(AUniversalOperationExecutor):
    """FLATTEN - Flatten nested arrays to a configurable depth."""
    OPERATION_NAME = "FLATTEN"
    OPERATION_TYPE = OperationType.ARRAY
    SUPPORTED_NODE_TYPES = []

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

    def _execute_op(self, node: Any, params: dict, context: ExecutionContext) -> dict:
        field: Optional[str] = params.get("field")
        depth: int = int(params.get("depth", 1))
        items = extract_items(node)

        if field:
            result_items = []
            for item in items:
                item_copy = item.copy() if isinstance(item, dict) else {"value": item}
                value = extract_field_value(item, field)
                if isinstance(value, list):
                    item_copy[field] = self._flatten_array(value, depth)
                result_items.append(item_copy)
            return {
                "items": result_items,
                "count": len(result_items),
                "total_items": len(items),
                "field": field,
                "depth": depth,
            }

        flattened = self._flatten_array(items, depth)
        return {
            "items": flattened,
            "count": len(flattened),
            "total_items": len(items),
            "field": None,
            "depth": depth,
        }

    def _flatten_array(self, values: list[Any], depth: int) -> list[Any]:
        if depth == 0:
            return list(values)
        if depth == -1:
            return list(self._flatten_recursive(values))
        return list(self._flatten_to_depth(values, depth))

    def _flatten_recursive(self, values: list[Any]):
        for value in values:
            if isinstance(value, list):
                yield from self._flatten_recursive(value)
            else:
                yield value

    def _flatten_to_depth(self, values: list[Any], depth: int):
        for value in values:
            if depth > 0 and isinstance(value, list):
                yield from self._flatten_to_depth(value, depth - 1)
            else:
                yield value


__all__ = ["FlattenExecutor"]
