package org.hzhub.factory;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hzhub.common.chat.service.chat.IChatModelService;
import org.hzhub.common.chat.domain.vo.chat.ChatModelVo;
import org.hzhub.service.embed.BaseEmbedModelService;
import org.hzhub.service.embed.MultiModalEmbedModelService;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 嵌入模型工厂服务类
 * 负责创建和管理各种嵌入模型实例
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class EmbeddingModelFactory {

    private final ApplicationContext applicationContext;

    private final IChatModelService chatModelService;

    // 模型缓存，使用ConcurrentHashMap保证线程安全
    private final Map<String, BaseEmbedModelService> modelCache = new ConcurrentHashMap<>();

    /**
     * 创建嵌入模型实例
     * 如果模型已存在于缓存中，则直接返回；否则创建新的实例
     *
     * @param embeddingModelName 嵌入模型名称
     */
    public BaseEmbedModelService createModel(String embeddingModelName) {
        return modelCache.computeIfAbsent(embeddingModelName, name -> {
            ChatModelVo modelConfig = chatModelService.selectModelByName(embeddingModelName);

            if (modelConfig == null) {
                throw new IllegalArgumentException("未找到模型配置，name=" + name);
            }
            return createModelInstance(modelConfig.getProviderCode(), modelConfig);
        });
    }

    /**
     * 检查模型是否支持多模态
     *
     * @param embeddingModelName 嵌入模型名称
     * @return boolean 如果模型支持多模态则返回true，否则返回false
     */
    public boolean isMultimodalModel(String embeddingModelName) {
        return createModel(embeddingModelName) instanceof MultiModalEmbedModelService;
    }

    /**
     * 创建多模态嵌入模型实例
     *
     * @param embeddingModelName 嵌入模型名称
     * @return MultiModalEmbedModelService 多模态嵌入模型服务实例
     * @throws IllegalArgumentException 当模型不支持多模态时抛出
     */
    public MultiModalEmbedModelService createMultimodalModel(String embeddingModelName) {
        BaseEmbedModelService model = createModel(embeddingModelName);
        if (model instanceof MultiModalEmbedModelService) {
            return (MultiModalEmbedModelService) model;
        }
        throw new IllegalArgumentException("该模型不支持多模态");
    }

    /**
     * 刷新模型缓存
     * 根据给定的嵌入模型ID从缓存中移除对应的模型
     *
     * @param embeddingModelId 嵌入模型的唯一标识ID
     */
    public void refreshModel(Long embeddingModelId) {
        // 从模型缓存中移除指定ID的模型
        modelCache.remove(embeddingModelId);
    }

    /**
     * 获取所有支持模型工厂的列表
     *
     * @return List<String> 支持的模型工厂名称列表
     */
    public List<String> getSupportedFactories() {
        return new ArrayList<>(applicationContext.getBeansOfType(BaseEmbedModelService.class)
                .keySet());
    }

    /**
     * 创建具体的模型实例
     * 根据提供的工厂名称和配置信息创建并配置模型实例
     *
     * @param factory 工厂名称，用于标识模型类型
     * @param config  模型配置信息
     * @return BaseEmbedModelService 配置好的模型实例
     * @throws IllegalArgumentException 当无法获取指定的模型实例时抛出
     */
    private BaseEmbedModelService createModelInstance(String factory, ChatModelVo config) {
        try {
            // 从Spring上下文中获取模型实例
            BaseEmbedModelService model = applicationContext.getBean(factory, BaseEmbedModelService.class);
            // 配置模型参数
            model.configure(config);
            log.info("成功创建嵌入模型: factory={}, modelId={}", config.getProviderCode(), config.getId());
            return model;
        } catch (NoSuchBeanDefinitionException e) {
            throw new IllegalArgumentException("获取不到嵌入模型: " + factory, e);
        }
    }
}
