#!/usr/bin/env python3
"""
EXISTS 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 ExistsExecutor(AUniversalOperationExecutor):
    """
    EXISTS operation executor - Field existence checking.
    Checks if a field/path exists in items (like SQL EXISTS, MongoDB $exists).
    Supports negation for NOT EXISTS semantics.
    O(n) scan over items.
    Capability: Universal
    Operation Type: FILTERING
    """
    OPERATION_NAME = "EXISTS"
    OPERATION_TYPE = OperationType.FILTERING
    SUPPORTED_NODE_TYPES = []  # Universal

    def _do_execute(self, action: QueryAction, context: ExecutionContext) -> ExecutionResult:
        """Execute EXISTS operation."""
        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"EXISTS requires 'field'. Got: {action.params}",
                action_type=self.OPERATION_NAME
            )

        node = context.node
        result_data = self._execute_exists(node, field, negate, path, context)

        return ExecutionResult(
            success=True,
            data=result_data,
            action_type=self.OPERATION_NAME,
            metadata={'matched_count': len(result_data.get('items', []))}
        )

    def _execute_exists(self, node: Any, field: str, negate: bool,
                        path: Optional[str], context: ExecutionContext) -> dict:
        """
        Execute EXISTS check - O(n) single-pass scan.
        For each item, checks whether the field is present (not just non-None,
        but actually exists as a key/attribute).
        """
        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:
            field_exists = self._field_exists(item, field)
            if (field_exists and not negate) or (not field_exists and negate):
                matched_items.append(item)

        op_label = 'NOT EXISTS' if negate else 'EXISTS'
        return {
            'items': matched_items,
            'count': len(matched_items),
            'total_items': len(items),
            'field': field,
            'operation': op_label
        }

    @staticmethod
    def _field_exists(item: Any, field: str) -> bool:
        """
        Check if a field exists on an item.
        Supports dot-notation for nested path existence.
        A field "exists" if the key is present in a dict or the attribute exists on an object,
        regardless of whether the value is None.
        """
        if item is None:
            return False

        if '.' in field:
            parts = field.split('.')
            current = item
            for part in parts:
                if current is None:
                    return False
                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 in item
        return hasattr(item, field)


__all__ = ['ExistsExecutor']
