package com.easyagents.federation.sql.adapter;

import com.easyagents.federation.sql.api.FederationSqlErrorCode;
import com.easyagents.federation.sql.api.FederationSqlException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;

/**
 * 支持显式注册与 ServiceLoader 的 Adapter 注册表。
 */
public final class FederationSqlAdapterRegistry {

    private final Map<String, FederationSqlAdapterProvider> providers;

    /**
     * 创建注册表；显式 Provider 优先于 ServiceLoader Provider。
     *
     * @param explicitProviders 显式 Provider
     * @param classLoader ServiceLoader 使用的类加载器
     */
    public FederationSqlAdapterRegistry(
        Collection<FederationSqlAdapterProvider> explicitProviders,
        ClassLoader classLoader
    ) {
        Map<String, FederationSqlAdapterProvider> loaded = new LinkedHashMap<>();
        ServiceLoader.load(FederationSqlAdapterProvider.class, classLoader)
            .forEach(provider -> putUnique(loaded, provider));
        if (explicitProviders != null) {
            Set<String> explicitIds = new HashSet<>();
            for (FederationSqlAdapterProvider provider : explicitProviders) {
                Objects.requireNonNull(provider, "adapter provider must not be null");
                if (!explicitIds.add(provider.adapterId())) {
                    throw new FederationSqlException(
                        FederationSqlErrorCode.SOURCE_DEFINITION_CONFLICT,
                        "duplicate explicitly registered adapter id: " + provider.adapterId()
                    );
                }
                loaded.put(provider.adapterId(), provider);
            }
        }
        this.providers = Map.copyOf(loaded);
    }

    private static void putUnique(
        Map<String, FederationSqlAdapterProvider> providers,
        FederationSqlAdapterProvider provider
    ) {
        FederationSqlAdapterProvider previous = providers.putIfAbsent(provider.adapterId(), provider);
        if (previous != null && !previous.getClass().equals(provider.getClass())) {
            throw new FederationSqlException(
                FederationSqlErrorCode.SOURCE_DEFINITION_CONFLICT,
                "duplicate adapter id from ServiceLoader: " + provider.adapterId()
            );
        }
    }

    /**
     * 查找 Adapter Provider。
     *
     * @param adapterId Adapter 标识
     * @return 可选 Provider
     */
    public Optional<FederationSqlAdapterProvider> find(String adapterId) {
        return Optional.ofNullable(providers.get(adapterId));
    }

    /**
     * 返回 Adapter Provider，缺失时抛出稳定错误。
     *
     * @param adapterId Adapter 标识
     * @return Provider
     */
    public FederationSqlAdapterProvider require(String adapterId) {
        return find(adapterId).orElseThrow(() -> new FederationSqlException(
            FederationSqlErrorCode.ADAPTER_NOT_FOUND,
            "adapter is not registered: " + adapterId
        ));
    }

    /**
     * 返回不可变 Provider 视图。
     *
     * @return Provider 映射
     */
    public Map<String, FederationSqlAdapterProvider> providers() {
        return providers;
    }
}
