#!/usr/bin/env python3
"""
IS_MISSING 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 IsMissingExecutor(AUniversalOperationExecutor):
    """Filter items where a field is missing (or present when negate=True). O(n)."""

    OPERATION_NAME = "IS_MISSING"
    OPERATION_TYPE = OperationType.FILTERING
    SUPPORTED_NODE_TYPES = []

    def _do_execute(self, action: QueryAction, context: ExecutionContext) -> ExecutionResult:
        params = action.params
        field = params.get("field")
        negate = params.get("negate", False)
        path = params.get("path", None)

        if not field:
            return ExecutionResult(
                success=False,
                data=None,
                error=f"IS_MISSING requires 'field'. Got: {action.params}",
                action_type=self.OPERATION_NAME,
            )

        result_data = self._execute_is_missing(context.node, field, negate, path)
        return ExecutionResult(
            success=True,
            data=result_data,
            action_type=self.OPERATION_NAME,
            metadata={"matched_count": len(result_data.get("items", []))},
        )

    @staticmethod
    def _field_exists(item: Any, field_path: str) -> bool:
        if item is None:
            return False

        if "." in field_path:
            current = item
            for part in field_path.split("."):
                if isinstance(current, dict):
                    if part not in current:
                        return False
                    current = current[part]
                elif hasattr(current, part):
                    current = getattr(current, part)
                else:
                    return False
            return True

        if isinstance(item, dict):
            return field_path in item
        return hasattr(item, field_path)

    def _execute_is_missing(
        self,
        node: Any,
        field: str,
        negate: bool,
        path: Optional[str],
    ) -> dict:
        if path:
            try:
                data = node.get(path, default=None)
            except Exception:
                data = None
        else:
            data = node

        items = extract_items(data)
        matched_items = []

        for item in items:
            exists = self._field_exists(item, field)
            is_match = (not exists) if not negate else exists
            if is_match:
                matched_items.append(item)

        return {
            "items": matched_items,
            "count": len(matched_items),
            "total_items": len(items),
            "field": field,
            "negate": bool(negate),
        }


__all__ = ["IsMissingExecutor"]
