#!/usr/bin/env python3
"""
RANDOM Executor
Company: eXonware.com
Author: eXonware Backend Team
Email: connect@exonware.com
Version: 0.9.0.6
"""

import math as _math
import random as _random
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 RandomExecutor(AUniversalOperationExecutor):
    OPERATION_NAME = "RANDOM"
    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)
        field: Optional[str] = params.get('field')
        as_field: Optional[str] = params.get('as_field', field)
        min_val = params.get('min_val')
        max_val = params.get('max_val')
        seed = params.get('seed')
        if seed is not None:
            _random.seed(seed)
        result_items = []
        for item in items:
            _ = extract_field_value(item, field) if field else item
            try:
                if min_val is not None and max_val is not None:
                    computed = _random.uniform(min_val, max_val)
                else:
                    computed = _random.random()
            except (TypeError, ValueError, ZeroDivisionError):
                computed = None
            if isinstance(item, dict):
                new_item = {**item, as_field: computed} if as_field else {**item}
                result_items.append(new_item)
            else:
                result_items.append(computed)
        return {'items': result_items, 'count': len(result_items), 'field': field}
