from asyncio import iscoroutinefunction
from typing import Self, Type, Union

from ariadne.types import Resolver

from api.broadcast import broadcast
from api_graphql.abc.field_builder_abc import FieldBuilderABC
from api_graphql.abc.input_abc import InputABC
from api_graphql.field.mutation_field import MutationField


class MutationFieldBuilder(FieldBuilderABC):

    def __init__(self, name: str):
        FieldBuilderABC.__init__(self, name)

        self._resolver = None
        self._input_type = None
        self._input_key = None

    def with_resolver(self, resolver: Resolver) -> Self:
        assert resolver is not None, "resolver cannot be None"

        self._resolver = resolver
        return self

    def with_broadcast(self, source: str):
        assert self._resolver is not None, "resolver cannot be None for broadcast"

        resolver = self._resolver

        async def resolver_wrapper(*args, **kwargs):
            result = (
                await resolver(*args, **kwargs)
                if iscoroutinefunction(resolver)
                else resolver(*args, **kwargs)
            )
            await broadcast.publish(f"{source}", result)
            return result

        self._resolver = resolver_wrapper
        return self

    def with_change_broadcast(self, source: str):
        assert self._resolver is not None, "resolver cannot be None for broadcast"

        resolver = self._resolver

        async def resolver_wrapper(*args, **kwargs):
            result = (
                await resolver(*args, **kwargs)
                if iscoroutinefunction(resolver)
                else resolver(*args, **kwargs)
            )
            await broadcast.publish(f"{source}", {})
            return result

        self._resolver = resolver_wrapper
        return self

    def with_input(
        self,
        input_type: Type[Union[InputABC, str, int, bool, list]],
        input_key: str = "input",
    ) -> Self:
        self._input_type = input_type
        self._input_key = input_key
        return self

    def build(self) -> MutationField:
        assert self._resolver is not None, "resolver cannot be None"
        return MutationField(
            self._name,
            self._require_any_permission,
            self._require_any,
            self._public,
            self._resolver,
            self._input_type,
            self._input_key,
        )
