from __future__ import annotations

from collections.abc import Iterable
from enum import Enum


def _unpack(objs):
    if isinstance(objs, Iterable) and not isinstance(objs, (str, bytes)):
        for obj in objs:
            yield from _unpack(obj)
    elif isinstance(objs, Enum):
        yield objs.value
    else:
        yield objs


def login_required(func):
    """Auth token is required for this endpoint."""

    func.login_required = True
    return func


def login_optional(func):
    """Auth token is optional for this endpoint."""

    func.login_optional = True
    return func


def skip_authorization(func):
    """Auth token is not required for this endpoint."""

    func.skip_authorization = True
    return func


def auth_by_cookie_or_header(func):
    """Auth token can be provided by cookie or header."""

    func.auth_by_cookie_or_header = True
    return func


def any_group_required(*groups):
    """Any of the mentioned groups is required."""

    def decorator(func):
        func.any_group_required = set(_unpack(groups))
        return login_required(func)

    return decorator


def all_groups_required(*groups):
    """All of the mentioned groups are required."""

    def decorator(func):
        func.all_groups_required = set(_unpack(groups))
        return login_required(func)

    return decorator


def groups_forbidden(*groups):
    """None of the mentioned groups are allowed."""

    def decorator(func):
        func.groups_forbidden = set(_unpack(groups))
        return login_required(func)

    return decorator


def authorizer(authorizer):
    """Custom the authorizer for this endpoint."""

    def decorator(func):
        func.authorizer = authorizer
        return login_required(func)

    return decorator


def ignore_site_ctx(func):
    """Ignore site context for this endpoint."""

    func.ignore_site_ctx = True
    return login_required(func)


def not_found_on_none(func):
    """If the return value is None, return HTTP 404 Not Found error."""

    func.not_found_on_none = True
    return func


def response_model(response_model):
    """[FastAPI only] Set response model for this endpoint."""

    def decorator(func):
        func.response_model = response_model
        return func

    return decorator


def skip_dbtransaction(func):
    """Skip database transaction for this endpoint."""

    func.skip_dbtransaction = True
    return func
