class SpringDIProcessor {

    Set<AnnotationInstance> getAnnotationsToAdd(
            final AnnotationTarget target,
            final Map<DotName, Set<DotName>> stereotypeScopes,
            final List<DotName> allArcScopes) {
        List<DotName> arcScopes = allArcScopes != null ? allArcScopes
                : Arrays.stream(BuiltinScope.values()).map(i -> i.getName()).collect(Collectors.toList());
        final Set<DotName> stereotypes = stereotypeScopes.keySet();

        final Set<AnnotationInstance> annotationsToAdd = new HashSet<>();

        //if it's a class, it's a Bean or a Bean producer
        if (target.kind() == AnnotationTarget.Kind.CLASS) {
            final ClassInfo classInfo = target.asClass();
            final Set<DotName> scopes = new HashSet<>();
            final Set<DotName> scopeStereotypes = new HashSet<>();
            final Set<String> names = new HashSet<>();
            final Set<DotName> clazzAnnotations = classInfo.annotations().keySet();

            for (AnnotationInstance instance : classInfo.classAnnotations()) {
                // make sure that we don't mix and match Spring and CDI annotations since this can cause a lot of problems
                if (arcScopes.contains(instance.name())) {
                    return annotationsToAdd;
                }
            }

            for (final DotName clazzAnnotation : clazzAnnotations) {
                if (stereotypes.contains(clazzAnnotation)) {
                    scopeStereotypes.add(clazzAnnotation);
                    final Set<DotName> scopeNames = stereotypeScopes.get(clazzAnnotation);
                    if (scopeNames != null) {
                        scopes.addAll(scopeNames);
                    }
                    if (SPRING_STEREOTYPE_ANNOTATIONS.contains(clazzAnnotation) && !isAnnotation(classInfo.flags())) {
                        names.add(getBeanNameFromStereotypeInstance(classInfo.classAnnotation(clazzAnnotation)));
                    }
                }
            }
            DotName declaredScope = getScope(classInfo);
            // @Named is a bean-defining annotation in Spring, but not in Arc.
            if (declaredScope == null && classInfo.classAnnotation(CDI_NAMED_ANNOTATION) != null) {
                declaredScope = CDI_SINGLETON_ANNOTATION; // implicit default scope in spring
            }
            final boolean isAnnotation = isAnnotation(classInfo.flags());
            if (declaredScope != null) {
                annotationsToAdd.add(create(
                        declaredScope,
                        target,
                        Collections.emptyList()));
            } else if (!(isAnnotation && scopes.isEmpty()) && !classInfo.annotations().containsKey(CONFIGURATION_ANNOTATION)) { // Annotations without an explicit scope shouldn't default to anything
                boolean shouldAdd = false;
                for (final DotName clazzAnnotation : clazzAnnotations) {
                    if (stereotypes.contains(clazzAnnotation) || scopeStereotypes.contains(clazzAnnotation)) {
                        shouldAdd = true;
                        break;
                    }
                }

                if (shouldAdd) {
                    final DotName scope = validateScope(classInfo, scopes, scopeStereotypes);
                    annotationsToAdd.add(create(
                            scope,
                            target,
                            Collections.emptyList()));
                }
            }
            final String name = validateName(classInfo, names);
            if (name != null) {
                annotationsToAdd.add(create(
                        CDI_NAMED_ANNOTATION,
                        target,
                        Collections.singletonList(AnnotationValue.createStringValue("value", name))));
            }

            if (classInfo.annotations().containsKey(CONFIGURATION_ANNOTATION)) {
                annotationsToAdd.add(create(
                        CDI_APP_SCOPED_ANNOTATION,
                        target,
                        Collections.emptyList()));
            }
            if (isAnnotation && !annotationsToAdd.isEmpty()) {
                annotationsToAdd.add(create(
                        DotNames.STEREOTYPE,
                        target,
                        Collections.emptyList()));
            }
        } else if (target.kind() == AnnotationTarget.Kind.FIELD) { // here we check for @Autowired and @Value annotations
            final FieldInfo fieldInfo = target.asField();
            if (fieldInfo.hasAnnotation(AUTOWIRED_ANNOTATION)) {
                annotationsToAdd.add(create(
                        CDI_INJECT_ANNOTATION,
                        target,
                        Collections.emptyList()));

                if (fieldInfo.hasAnnotation(SPRING_QUALIFIER_ANNOTATION)) {
                    final AnnotationInstance annotation = fieldInfo.annotation(SPRING_QUALIFIER_ANNOTATION);
                    final AnnotationValue annotationValue = annotation.value();
                    if (annotationValue != null) {
                        final String value = annotationValue.asString();
                        annotationsToAdd.add(create(
                                CDI_NAMED_ANNOTATION,
                                target,
                                Collections.singletonList((AnnotationValue.createStringValue("value", value)))));
                    }
                }
            } else if (fieldInfo.hasAnnotation(SPRING_VALUE_ANNOTATION)) {
                final AnnotationInstance annotation = fieldInfo.annotation(SPRING_VALUE_ANNOTATION);
                addSpringValueAnnotations(target, annotation, true, annotationsToAdd);
            }
        } else if (target.kind() == AnnotationTarget.Kind.METHOD) {
            final MethodInfo methodInfo = target.asMethod();
            if (methodInfo.hasAnnotation(BEAN_ANNOTATION)
                    && methodInfo.declaringClass().classAnnotation(CONFIGURATION_ANNOTATION) != null) {
                annotationsToAdd.add(create(
                        CDI_PRODUCES_ANNOTATION,
                        target,
                        Collections.emptyList()));
                DotName declaredScope = getScope(methodInfo);
                // Non-spring specific annotations are processed by Arc
                if (declaredScope == null && !methodInfo.hasAnnotation(CDI_SINGLETON_ANNOTATION)) {
                    declaredScope = CDI_SINGLETON_ANNOTATION; // implicit default scope in spring
                }
                if (declaredScope != null) {
                    annotationsToAdd.add(create(
                            declaredScope,
                            target,
                            Collections.emptyList()));
                }

                String beanName = getBeanNameFromBeanInstance(methodInfo.annotation(BEAN_ANNOTATION));
                annotationsToAdd.add(create(
                        CDI_NAMED_ANNOTATION,
                        target,
                        Collections.singletonList(AnnotationValue.createStringValue("value", beanName))));
            } else if (methodInfo.hasAnnotation(AUTOWIRED_ANNOTATION)) {
                annotationsToAdd.add(create(
                        CDI_INJECT_ANNOTATION,
                        target,
                        Collections.emptyList()));
            }

            // add method parameter conversion annotations
            for (AnnotationInstance annotation : methodInfo.annotations()) {
                if (annotation.target().kind() == AnnotationTarget.Kind.METHOD_PARAMETER) {
                    if (annotation.name().equals(SPRING_QUALIFIER_ANNOTATION)) {
                        final AnnotationValue annotationValue = annotation.value();
                        if (annotationValue != null) {
                            final String value = annotationValue.asString();
                            annotationsToAdd.add(create(
                                    CDI_NAMED_ANNOTATION,
                                    annotation.target(),
                                    Collections.singletonList(AnnotationValue.createStringValue("value", value))));
                        }
                    } else if (annotation.name().equals(SPRING_VALUE_ANNOTATION)) {
                        addSpringValueAnnotations(annotation.target(), annotation, false, annotationsToAdd);
                    }
                }
            }

        }
        return annotationsToAdd;
    }

}