#!/usr/bin/env python3
"""
IF_EXPR 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 IfExprExecutor(AUniversalOperationExecutor):
    """
    IF_EXPR operation executor - Ternary conditional expression per item.

    For each item: if *condition* is true, yields *then_value*; otherwise *else_value*.

    params:
        condition:  dict with {field, operator, value} describing the predicate
        then_value: value (or field name prefixed with '$') to use when condition is true
        else_value: value (or field name prefixed with '$') to use when condition is false
        output:     output field name for the result (default: '_if_result')

    Time Complexity: O(n) single pass
    Capability: Universal
    Operation Type: ADVANCED (conditional)
    """
    OPERATION_NAME = "IF_EXPR"
    OPERATION_TYPE = OperationType.ADVANCED
    SUPPORTED_NODE_TYPES = []

    OPERATORS = {
        '==': lambda a, b: a == b,
        '!=': lambda a, b: a != b,
        '>': lambda a, b: a > b,
        '>=': lambda a, b: a >= b,
        '<': lambda a, b: a < b,
        '<=': lambda a, b: a <= b,
        'in': lambda a, b: a in b,
        'not in': lambda a, b: a not in b,
        'contains': lambda a, b: b in a,
        'is_none': lambda a, b: a is None,
        'is_not_none': lambda a, b: a is not None,
    }

    def _do_execute(self, action: QueryAction, context: ExecutionContext) -> ExecutionResult:
        params = action.params
        node = context.node
        result_data = self._execute_op(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:
        items = extract_items(node)
        condition = params.get('condition', {})
        then_value = params.get('then_value')
        else_value = params.get('else_value')
        output_field = params.get('output', '_if_result')

        result_items = []
        true_count = 0

        for item in items:
            item_copy = item.copy() if isinstance(item, dict) else {'value': item}
            if self._check_condition(item, condition):
                item_copy[output_field] = self._resolve_value(item, then_value)
                true_count += 1
            else:
                item_copy[output_field] = self._resolve_value(item, else_value)
            result_items.append(item_copy)

        return {
            'items': result_items,
            'count': len(result_items),
            'total_items': len(items),
            'true_count': true_count,
            'false_count': len(items) - true_count,
        }

    def _check_condition(self, item: Any, condition: Any) -> bool:
        if condition is None or condition == {}:
            return True
        if callable(condition):
            try:
                return bool(condition(item))
            except Exception:
                return False
        if isinstance(condition, dict):
            field = condition.get('field', '')
            op = condition.get('operator', '==')
            expected = condition.get('value')
            actual = extract_field_value(item, field) if field else item
            fn = self.OPERATORS.get(op)
            if fn is None:
                return False
            try:
                return fn(actual, expected)
            except (TypeError, ValueError):
                return False
        return bool(condition)

    @staticmethod
    def _resolve_value(item: Any, value: Any) -> Any:
        """If value is a string starting with '$', treat it as a field reference."""
        if isinstance(value, str) and value.startswith('$'):
            return extract_field_value(item, value[1:])
        return value

__all__ = ['IfExprExecutor']
