// Path: src/main/java/no/saua/remock/internal/SpyDefinition.java
// public static class SpyInitializer implements BeanPostProcessor, Resettable {
// 
//     private Set<SpyDefinition> spyDefinitions = new HashSet<>();
//     private List<Object> spies = new ArrayList<>();
// 
//     public SpyInitializer(Set<SpyDefinition> spyDefinitions) {
//         this.spyDefinitions = spyDefinitions;
//     }
// 
//     @Override
//     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//         return bean;
//     }
// 
//     @Override
//     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//         for (SpyDefinition spyDefinition : spyDefinitions) {
//             if (spyDefinition.matches(bean.getClass(), beanName)) {
//                 Object spy = Mockito.spy(bean);
//                 spies.add(spy);
//                 return spy;
//             }
//         }
//         return bean;
//     }
// 
//     @Override
//     public void reset() {
//         for (Object spy: spies) {
//             Mockito.reset(spy);
//         }
//     }
// }


import no.saua.remock.internal.SpyDefinition.SpyInitializer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
import java.lang.reflect.Field;
            super.prepareContext(context, mergedConfig);
            prepareContextCommon(context, mergedConfig);
        }
    }

    public static void prepareContextCommon(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
        if (!(mergedConfig instanceof RemockMergedContextConfiguration)) {
            throw new AssertionError("MergedContextConfiguration is not a RemockMergedContextConfiguration. This should not happen.");
        }

        RemockConfiguration remockConfig = ((RemockMergedContextConfiguration) mergedConfig).getRemockConfiguration();
        try {
            Field beanFactoryField = GenericApplicationContext.class.getDeclaredField("beanFactory");
            beanFactoryField.setAccessible(true);
            BeanFactory beanFactory = createBeanFactory(remockConfig);
            beanFactoryField.set(context, beanFactory);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException("Unable to perform bean factory hack", e);
        }
    }

    public static RemockBeanFactory createBeanFactory(RemockConfiguration remockConfig) {
        RemockBeanFactory remockBeanFactory = new RemockBeanFactory(remockConfig);

        // :: Initialize mock definitions
        for (SpringBeanDefiner mockDefinition : remockConfig.getDefiners()) {
            remockBeanFactory.registerMockBeanDefinition(mockDefinition.getBeanName(), mockDefinition.getBeanDefinition());
        }

        // :: Register the spy initializer
// Path: src/main/java/no/saua/remock/internal/SpyDefinition.java
// public static class SpyInitializer implements BeanPostProcessor, Resettable {
// 
//     private Set<SpyDefinition> spyDefinitions = new HashSet<>();
//     private List<Object> spies = new ArrayList<>();
// 
//     public SpyInitializer(Set<SpyDefinition> spyDefinitions) {
//         this.spyDefinitions = spyDefinitions;
//     }
// 
//     @Override
//     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//         return bean;
//     }
// 
//     @Override
//     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//         for (SpyDefinition spyDefinition : spyDefinitions) {
//             if (spyDefinition.matches(bean.getClass(), beanName)) {
//                 Object spy = Mockito.spy(bean);
//                 spies.add(spy);
//                 return spy;
//             }
//         }
//         return bean;
//     }
// 
//     @Override
//     public void reset() {
//         for (Object spy: spies) {
//             Mockito.reset(spy);
//         }
//     }
// }


// Path: src/main/java/no/saua/remock/internal/RemockContextClassLoader.java
import no.saua.remock.internal.SpyDefinition.SpyInitializer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
import java.lang.reflect.Field;

            super.prepareContext(context, mergedConfig);
            prepareContextCommon(context, mergedConfig);
        }
    }

    public static void prepareContextCommon(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
        if (!(mergedConfig instanceof RemockMergedContextConfiguration)) {
            throw new AssertionError("MergedContextConfiguration is not a RemockMergedContextConfiguration. This should not happen.");
        }

        RemockConfiguration remockConfig = ((RemockMergedContextConfiguration) mergedConfig).getRemockConfiguration();
        try {
            Field beanFactoryField = GenericApplicationContext.class.getDeclaredField("beanFactory");
            beanFactoryField.setAccessible(true);
            BeanFactory beanFactory = createBeanFactory(remockConfig);
            beanFactoryField.set(context, beanFactory);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException("Unable to perform bean factory hack", e);
        }
    }

    public static RemockBeanFactory createBeanFactory(RemockConfiguration remockConfig) {
        RemockBeanFactory remockBeanFactory = new RemockBeanFactory(remockConfig);

        // :: Initialize mock definitions
        for (SpringBeanDefiner mockDefinition : remockConfig.getDefiners()) {
            remockBeanFactory.registerMockBeanDefinition(mockDefinition.getBeanName(), mockDefinition.getBeanDefinition());
        }

        // :: Register the spy initializer
        remockBeanFactory.registerSingleton("$RemockSpyInitializer$", new SpyInitializer(remockConfig.getSpies()));