package ru.yandex.qe.dispenser.domain.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;
import ru.yandex.qe.dispenser.domain.hierarchy.Session;

@Aspect
public class HierarchyRequiredAspect extends AspectBase {
    private static final Logger LOG = LoggerFactory.getLogger(HierarchyRequired.class);
    private static final ThreadLocal<Boolean> isDisabled = ThreadLocal.withInitial(() -> false);

    @Around("execution(public * *(..)) && @annotation(hierarchyRequired)")
    public Object around(final @NotNull ProceedingJoinPoint jp, final @NotNull HierarchyRequired hierarchyRequired) throws Throwable {
        final Hierarchy hierarchy = Session.HIERARCHY.get();
        final boolean hasHierarchy = hierarchy != null && !hierarchy.isSql();
        if (!hasHierarchy) {
            LOG.error("hierarchy is required but not found here (target {}::{})", jp.getThis().getClass().getName(), jp.getSignature().getName());
        }
        if (hasHierarchy || !hierarchyRequired.canReject() || isDisabled.get()) {
            return jp.proceed();
        } else {
            throw new RuntimeException("Execution of method is rejected due to absent hierarchy in cache (target " + jp.getThis().getClass().getName() + "::" + jp.getSignature().getName() + ")");
        }
    }


    public static void runWithDisabledCheck(@NotNull final Runnable r) {
        try {
            isDisabled.set(true);
            r.run();
        } finally {
            isDisabled.set(false);
        }
    }
}
