#!/usr/bin/env python3
"""
UNWIND 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 UnwindExecutor(AUniversalOperationExecutor):
    """UNWIND - Expand array field into separate rows."""
    OPERATION_NAME = "UNWIND"
    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")
        preserve_null: bool = bool(params.get("preserve_null", False))
        items = extract_items(node)

        if not field:
            return {"items": items, "count": len(items), "total_items": len(items)}

        unwound_items = list(self._unwind_generator(items, field, preserve_null))
        return {
            "items": unwound_items,
            "count": len(unwound_items),
            "total_items": len(items),
            "field": field,
            "preserve_null": preserve_null,
        }

    def _unwind_generator(self, items: list[Any], field: str, preserve_null: bool):
        """Yield unwound rows lazily for memory efficiency."""
        for item in items:
            item_copy = item.copy() if isinstance(item, dict) else {"value": item}
            field_value = extract_field_value(item, field)

            if isinstance(field_value, list):
                if field_value:
                    for element in field_value:
                        row = item_copy.copy()
                        self._set_field_value(row, field, element)
                        yield row
                elif preserve_null:
                    row = item_copy.copy()
                    self._set_field_value(row, field, None)
                    yield row
            elif preserve_null:
                row = item_copy.copy()
                self._set_field_value(row, field, field_value)
                yield row

    @staticmethod
    def _set_field_value(item: dict[str, Any], field_path: str, value: Any) -> None:
        """Set simple or dotted path fields on dict items."""
        if "." not in field_path:
            item[field_path] = value
            return

        parts = field_path.split(".")
        current: Any = item
        for part in parts[:-1]:
            next_value = current.get(part)
            if not isinstance(next_value, dict):
                next_value = {}
                current[part] = next_value
            current = next_value
        current[parts[-1]] = value


__all__ = ["UnwindExecutor"]
