#  Copyright (C) 2025
#  ABM, Moscow
#
#  UNPUBLISHED PROPRIETARY MATERIAL.
#  ALL RIGHTS RESERVED.
#
#  Authors: Mike Orlov <m.orlov@abm-jsc.ru>
import asyncio
import itertools
from dataclasses import dataclass
from typing import Callable, Any

from async_tools import acall
from frozendict import frozendict
from http_tools import IncomingRequest
from init_helpers import NoValue

from .parameter_aggregation import ParameterAggregation
from ..call_parameter import CallParameter
from ..spec_parameter import SpecParameter


@dataclass(frozen=True, kw_only=True)
class CallTemplate(ParameterAggregation):
    func: Callable
    args: tuple[CallParameter, ...]
    kwargs: dict[str, CallParameter]

    def __init__(self, func: Callable, *args: CallParameter, **kwargs: CallParameter):
        object.__setattr__(self, 'schema', NoValue)
        object.__setattr__(self, 'func', func)
        object.__setattr__(self, 'args', args)
        object.__setattr__(self, 'kwargs', kwargs)

    async def get(self, incoming_request: IncomingRequest, security_kwargs: dict[str, Any]) -> Any:
        args = await asyncio.gather(*[arg.get(incoming_request, security_kwargs) for arg in self.args])
        kwarg_values = await asyncio.gather(*[v.get(incoming_request, security_kwargs) for v in self.kwargs.values()])
        args = [value for value in args if value is not NoValue]
        kwargs = {key: value for key, value in zip(kwarg_values, self.kwargs) if value is not NoValue}
        result = await acall(self.func(*args, **kwargs))
        return result

    def get_spec_parameters(self) -> frozendict['SpecParameter', None]:
        result = {}
        for arg in itertools.chain(self.args, self.kwargs.values()):
            result |= arg.get_spec_parameters()
        return frozendict(result)
