package com.pavis.admin.aigc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pavis.admin.aigc.constant.ModelConst;
import com.pavis.admin.aigc.core.llm.provider.build.ModelBuildHandler;
import com.pavis.admin.aigc.enums.ModelTypeEnum;
import com.pavis.admin.aigc.mapper.ModelSecretMapper;
import com.pavis.admin.aigc.model.entity.ModelSecretDO;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.image.ImageModel;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import top.continew.starter.extension.crud.service.BaseServiceImpl;
import com.pavis.admin.aigc.mapper.ModelMapper;
import com.pavis.admin.aigc.model.entity.ModelDO;
import com.pavis.admin.aigc.model.query.ModelQuery;
import com.pavis.admin.aigc.model.req.ModelReq;
import com.pavis.admin.aigc.model.resp.ModelDetailResp;
import com.pavis.admin.aigc.model.resp.ModelResp;
import com.pavis.admin.aigc.service.ModelService;

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

/**
 * AIGC模型配置业务实现
 *
 * @author semi
 * @since 2025/05/26 17:28
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ModelServiceImpl extends BaseServiceImpl<ModelMapper, ModelDO, ModelResp, ModelDetailResp, ModelQuery, ModelReq> implements ModelService {

    private final ModelSecretMapper modelSecretMapper;

    @Autowired
    private List<ModelBuildHandler> modelBuildHandlers;

    private final List<ModelResp> modelStore = new ArrayList<>();
    private final Map<String, StreamingChatLanguageModel> streamingChatMap = new ConcurrentHashMap<>();
    private final Map<String, ChatLanguageModel> chatLanguageMap = new ConcurrentHashMap<>();
    private final Map<String, EmbeddingModel> embeddingModelMap = new ConcurrentHashMap<>();
    private final Map<String, ImageModel> imageModelMap = new ConcurrentHashMap<>();

    public void insModelAndSecret(ModelReq modelReq) {
        // 1. 将modelReq部分字段cope到modelDO实体中，并进行insert
        ModelDO modelDO = new ModelDO();
        BeanUtil.copyProperties(modelReq, modelDO);
        baseMapper.insert(modelDO);
        // 2. 获取模型id，将模型表跟模型配置表关联起来,modelReq中已经带过来需要配置的配置数据
        ModelSecretDO modelSecretDO = new ModelSecretDO();
        modelSecretDO.setModelId(modelDO.getId());
        BeanUtil.copyProperties(modelReq, modelSecretDO);
        modelSecretMapper.insert(modelSecretDO);
    }

    @Override
    public List<ModelResp> selModelAndSecrt() {
        return baseMapper.selModelAndSecret();
    }

    @Override
    public List<ModelResp> selModelAndSecrtList(ModelQuery modelQuery) {
        return baseMapper.selModelAndSecretList(modelQuery.getType(), modelQuery.getProvider());
    }

    @Override
    public void updateModelAndSecrt(ModelResp modelResp) {
        ModelDO modelDO = new ModelDO();
        BeanUtil.copyProperties(modelResp, modelDO);
        baseMapper.updateById(modelDO);
        ModelSecretDO modelSecretDO = new ModelSecretDO();
        BeanUtil.copyProperties(modelResp, modelSecretDO);
        modelSecretMapper.update(modelSecretDO, new QueryWrapper<ModelSecretDO>().eq("model_id", modelResp.getId()));
    }

    @Override
    public void delModelAndSecrt(List<Long> ids) {
        for (Long id : ids) {
            ModelDO modelDO = baseMapper.selectById(id);
            if (modelDO != null) {
                modelSecretMapper.delete(new QueryWrapper<ModelSecretDO>().eq("model_id", modelDO.getId()));
                baseMapper.deleteById(id);
            }
        }
    }
    // @Override
    // public List<AigcModel> getChatModels() {
    //     List<AigcModel> list = baseMapper.selectList(Wrappers.<AigcModel>lambdaQuery()
    //             .eq(AigcModel::getType, ModelTypeEnum.CHAT.name()));
    //     list.forEach(this::hide);
    //     return list;
    // }

    // @Override
    // public List<AigcModel> getImageModels() {
    //     List<AigcModel> list = baseMapper.selectList(Wrappers.<AigcModel>lambdaQuery()
    //             .eq(AigcModel::getType, ModelTypeEnum.TEXT_IMAGE.name()));
    //     list.forEach(this::hide);
    //     return list;
    // }

    // @Override
    // public List<AigcModel> getEmbeddingModels() {
    //     List<AigcModel> list = baseMapper.selectList(Wrappers.<AigcModel>lambdaQuery()
    //             .eq(AigcModel::getType, ModelTypeEnum.EMBEDDING.name()));
    //     list.forEach(this::hide);
    //     return list;
    // }

    @Override
    public List<ModelResp> list(ModelResp data) {
        List<ModelDO> list = this.list(Wrappers.<ModelDO>lambdaQuery()
            .eq(StrUtil.isNotBlank(data.getType()), ModelDO::getType, data.getType())
            .eq(StrUtil.isNotBlank(data.getProvider()), ModelDO::getProvider, data.getProvider()));
        // copy实体
        List<ModelResp> respList = BeanUtil.copyToList(list, ModelResp.class);
        respList.forEach(this::hideResp);
        return respList;
    }

    // @Override
    // public Page<AigcModel> page(AigcModel data, QueryPage queryPage) {
    //     Page<AigcModel> page = new Page<>(queryPage.getPage(), queryPage.getLimit());
    //     Page<AigcModel> iPage = this.page(page, Wrappers.<AigcModel>lambdaQuery().eq(AigcModel::getProvider, data.getProvider()));
    //     iPage.getRecords().forEach(this::hide);
    //     return iPage;
    // }

    // @Override
    // public AigcModel selectById(String id) {
    //     AigcModel model = this.getById(id);
    //     hide(model);
    //     return model;
    // }

    // private void hide(ModelDO model) {
    //     if (model == null || StrUtil.isBlank(model.getApiKey())) {
    //         return;
    //     }
    //     String key = StrUtil.hide(model.getApiKey(), 3, model.getApiKey().length() - 4);
    //     model.setApiKey(key);
    //
    //     if (StrUtil.isBlank(model.getSecretKey())) {
    //         return;
    //     }
    //     String sec = StrUtil.hide(model.getSecretKey(), 3, model.getSecretKey().length() - 4);
    //     model.setSecretKey(sec);
    // }
    private void hideResp(ModelResp model) {
        // 通过modelId获取相应的apikey和SecretKey
        ModelSecretDO modelSecretDO = modelSecretMapper.selectOne(new QueryWrapper<ModelSecretDO>().eq("model_id", model
            .getModel()));
        if (modelSecretDO == null || StrUtil.isBlank(modelSecretDO.getApiKey())) {
            return;
        }
        String key = StrUtil.hide(modelSecretDO.getApiKey(), 3, modelSecretDO.getApiKey().length() - 4);
        model.setApiKey(key);

        if (StrUtil.isBlank(modelSecretDO.getSecretKey())) {
            return;
        }
        String sec = StrUtil.hide(modelSecretDO.getSecretKey(), 3, modelSecretDO.getSecretKey().length() - 4);
        model.setSecretKey(sec);
    }

    // LANGCHAT
    @Async
    @PostConstruct
    public void init() {
        modelStore.clear();
        streamingChatMap.clear();
        chatLanguageMap.clear();
        embeddingModelMap.clear();
        imageModelMap.clear();

        List<ModelResp> list = baseMapper.selectByModel();
        list.forEach(model -> {
            if (Objects.equals(model.getBaseUrl(), "")) {
                model.setBaseUrl(null);
            }

            chatHandler(model);
            embeddingHandler(model);
            imageHandler(model);
        });

        modelStore.forEach(i -> log.info("已成功注册模型：{} -- {}， 模型配置：{}", i.getProvider(), i.getType(), i));
    }

    private void chatHandler(ModelResp model) {
        try {
            String type = model.getType();
            if (!ModelTypeEnum.CHAT.name().equals(type)) {
                return;
            }
            modelBuildHandlers.forEach(x -> {
                StreamingChatLanguageModel streamingChatLanguageModel = x.buildStreamingChat(model);
                if (ObjectUtil.isNotEmpty(streamingChatLanguageModel)) {
                    streamingChatMap.put(model.getId().toString(), streamingChatLanguageModel);
                    modelStore.add(model);
                }

                ChatLanguageModel languageModel = x.buildChatLanguageModel(model);
                if (ObjectUtil.isNotEmpty(languageModel)) {
                    chatLanguageMap.put(model.getId() + ModelConst.TEXT_SUFFIX, languageModel);
                }
            });
        } catch (Exception e) {
            log.error("model 【 id: {} name: {}】streaming chat 配置报错", model.getId(), model.getName());
        }
    }

    private void embeddingHandler(ModelResp model) {
        try {
            String type = model.getType();
            if (!ModelTypeEnum.EMBEDDING.name().equals(type)) {
                return;
            }
            modelBuildHandlers.forEach(x -> {
                EmbeddingModel embeddingModel = x.buildEmbedding(model);
                if (ObjectUtil.isNotEmpty(embeddingModel)) {
                    embeddingModelMap.put(model.getId().toString(), embeddingModel);
                    modelStore.add(model);
                }
            });

        } catch (Exception e) {
            log.error("model 【id{} name{}】 embedding 配置报错", model.getId(), model.getName());
        }
    }

    private void imageHandler(ModelResp model) {
        try {
            String type = model.getType();
            if (!ModelTypeEnum.TEXT_IMAGE.name().equals(type)) {
                return;
            }
            modelBuildHandlers.forEach(x -> {
                ImageModel imageModel = x.buildImage(model);
                if (ObjectUtil.isNotEmpty(imageModel)) {
                    imageModelMap.put(model.getId().toString(), imageModel);
                    modelStore.add(model);
                }
            });
        } catch (Exception e) {
            log.error("model 【id{} name{}】 image 配置报错", model.getId(), model.getName());
        }
    }

    public StreamingChatLanguageModel getStreamingChatModel(String modelId) {
        return streamingChatMap.get(modelId);
    }

    public boolean containsStreamingChatModel(String modelId) {
        return streamingChatMap.containsKey(modelId);
    }

    public ChatLanguageModel getChatLanguageModel(String modelId) {
        return chatLanguageMap.get(modelId + ModelConst.TEXT_SUFFIX);
    }

    public boolean containsChatLanguageModel(String modelId) {
        return chatLanguageMap.containsKey(modelId + ModelConst.TEXT_SUFFIX);
    }

    public EmbeddingModel getEmbeddingModel(String modelId) {
        return embeddingModelMap.get(modelId);
    }

    public boolean containsEmbeddingModel(String modelId) {
        return embeddingModelMap.containsKey(modelId);
    }

    public ImageModel getImageModel(String modelId) {
        return imageModelMap.get(modelId);
    }

    public boolean containsImageModel(String modelId) {
        return imageModelMap.containsKey(modelId);
    }
}