#!/usr/bin/env python3
"""
COALESCE 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 CoalesceExecutor(AUniversalOperationExecutor):
    """
    COALESCE operation executor - Returns first non-None value from a list of fields.

    For each item, iterates through the specified fields and returns the value
    of the first field that is not None. Falls back to `default` when all are None.

    params:
        fields:  list of field names to check (in priority order)
        default: fallback value when all fields are None (default: None)
        output:  output field name for the result (default: '_coalesce')

    Time Complexity: O(n*f) where n=items, f=fields
    Capability: Universal
    Operation Type: ADVANCED (conditional)
    """
    OPERATION_NAME = "COALESCE"
    OPERATION_TYPE = OperationType.ADVANCED
    SUPPORTED_NODE_TYPES = []

    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)
        fields = params.get('fields', [])
        default = params.get('default', None)
        output_field = params.get('output', '_coalesce')

        result_items = []
        default_used_count = 0

        for item in items:
            item_copy = item.copy() if isinstance(item, dict) else {'value': item}
            resolved = self._first_non_none(item, fields)
            if resolved is None:
                resolved = default
                default_used_count += 1
            item_copy[output_field] = resolved
            result_items.append(item_copy)

        return {
            'items': result_items,
            'count': len(result_items),
            'total_items': len(items),
            'default_used_count': default_used_count,
        }

    @staticmethod
    def _first_non_none(item: Any, fields: list) -> Any:
        """Return the value of the first field that is not None."""
        for field in fields:
            value = extract_field_value(item, field)
            if value is not None:
                return value
        return None

__all__ = ['CoalesceExecutor']
