from typing import AsyncGenerator

from api.broadcast import broadcast
from api.route import Route
from api_graphql.abc.subscription_abc import SubscriptionABC
from api_graphql.field.subscription_field_builder import SubscriptionFieldBuilder
from api_graphql.require_any_resolvers import has_assigned_user_spaces
from service.permission.permissions_enum import Permissions


class Subscription(SubscriptionABC):
    def __init__(self):
        SubscriptionABC.__init__(self)

        self.subscribe(
            SubscriptionFieldBuilder("ping")
            .with_resolver(lambda message, *_: message.message)
            .with_public(True)
        )

        self.subscribe(
            SubscriptionFieldBuilder("apiKeyChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any_permission([Permissions.api_keys])
        )

        self.subscribe(
            SubscriptionFieldBuilder("featureFlagChange")
            .with_resolver(lambda message, *_: message.message)
            .with_public(True)
        )

        self.subscribe(
            SubscriptionFieldBuilder("roleChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any_permission([Permissions.roles])
        )

        self.subscribe(
            SubscriptionFieldBuilder("settingChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any_permission([Permissions.settings])
        )

        self.subscribe(
            SubscriptionFieldBuilder("userChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any_permission([Permissions.users])
        )

        self.subscribe(
            SubscriptionFieldBuilder("userSettingChange")
            .with_resolver(lambda message, *_: message.message)
            .with_public(True)
        )

        async def _user_logout_generator(*args, **kwargs) -> AsyncGenerator[str, None]:
            async with broadcast.subscribe(channel="userLogout") as subscriber:
                async for message in subscriber:
                    if message.message == (await Route.get_user()).id:
                        yield message

        self.subscribe(
            SubscriptionFieldBuilder("userLogout")
            .with_resolver(lambda message, *_: message.message)
            .with_generator(_user_logout_generator)
            .with_public(True)
        )

        self.subscribe(
            SubscriptionFieldBuilder("domainChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any_permission([Permissions.domains])
        )
        self.subscribe(
            SubscriptionFieldBuilder("userSpaceChange")
            .with_resolver(lambda message, *_: message.message)
            .with_public(True)
        )
        self.subscribe(
            SubscriptionFieldBuilder("groupChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any([Permissions.groups], [has_assigned_user_spaces])
        )
        self.subscribe(
            SubscriptionFieldBuilder("shortUrlChange")
            .with_resolver(lambda message, *_: message.message)
            .with_require_any([Permissions.short_urls], [has_assigned_user_spaces])
        )
