package dev.elaine.springlab.ioc;

import java.lang.reflect.Constructor;
import java.util.LinkedHashMap;
import java.util.Map;

public final class MiniApplicationContext {
    private final Map<Class<?>, BeanDefinition> definitions = new LinkedHashMap<>();
    private final Map<Class<?>, Object> singletons = new LinkedHashMap<>();

    public MiniApplicationContext register(Class<?>... beanTypes) {
        for (Class<?> beanType : beanTypes) {
            definitions.put(beanType, new BeanDefinition(beanType));
        }
        return this;
    }

    public <T> T getBean(Class<T> beanType) {
        Class<?> implementationType = resolveImplementation(beanType);
        Object bean = singletons.get(implementationType);
        if (bean == null) {
            bean = createBean(implementationType);
            singletons.put(implementationType, bean);
        }
        return beanType.cast(bean);
    }

    private Class<?> resolveImplementation(Class<?> requestedType) {
        if (definitions.containsKey(requestedType)) {
            return requestedType;
        }
        Class<?>[] candidates = definitions.keySet().stream()
                .filter(requestedType::isAssignableFrom)
                .toArray(Class<?>[]::new);
        if (candidates.length != 1) {
            throw new IllegalArgumentException(
                    "Bean 候选数量不是 1: " + requestedType.getName() + " -> " + candidates.length);
        }
        return candidates[0];
    }

    private Object createBean(Class<?> beanType) {
        BeanDefinition definition = definitions.get(beanType);
        if (definition == null) {
            throw new IllegalArgumentException("未注册 Bean: " + beanType.getName());
        }
        try {
            Constructor<?> constructor = definition.beanType().getDeclaredConstructors()[0];
            Object[] dependencies = new Object[constructor.getParameterCount()];
            for (int index = 0; index < dependencies.length; index++) {
                dependencies[index] = getBean(constructor.getParameterTypes()[index]);
            }
            constructor.setAccessible(true);
            return constructor.newInstance(dependencies);
        } catch (ReflectiveOperationException error) {
            throw new IllegalStateException("创建 Bean 失败: " + beanType.getName(), error);
        }
    }

    public record BeanDefinition(Class<?> beanType) {}
}
