package cn.iocoder.yudao.module.llm.service.conversation;

import cn.hutool.json.JSONArray;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.llm.controller.admin.application.vo.ApplicationRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.application.vo.ApplicationSaveReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ChatReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ChatRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ConversationPageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ConversationSaveReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.datarefluxdata.vo.DataRefluxDataSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.conversation.ConversationDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.knowledgedocuments.KnowledgeDocumentsDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO;
import cn.iocoder.yudao.module.llm.dal.mysql.conversation.ConversationMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.knowledgedocuments.KnowledgeDocumentsMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties;
import cn.iocoder.yudao.module.llm.service.application.ApplicationService;
import cn.iocoder.yudao.module.llm.service.basemodel.BaseModelService;
import cn.iocoder.yudao.module.llm.service.datarefluxdata.DataRefluxDataService;
import cn.iocoder.yudao.module.llm.service.http.ModelService;
import cn.iocoder.yudao.module.llm.service.http.vo.*;
import cn.iocoder.yudao.module.llm.service.prompttemplates.PromptTemplatesService;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.llm.enums.ErrorCodeConstants.*;

/**
 * 大模型对话记录 Service 实现类
 *
 * @author 华大大模型
 */
@Service
@Validated
public class ConversationServiceImpl implements ConversationService {

    @Resource
    private ConversationMapper conversationMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ModelService modelService;
    @Resource
    private BaseModelService baseModelService;
    @Resource
    private DataRefluxDataService dataRefluxDataService;
    @Resource
    private ModelServiceMapper modelServiceMapper;
    @Resource
    private ApplicationService applicationService;
    @Resource
    private PromptTemplatesService promptTemplatesService;
    @Resource
    private KnowledgeDocumentsMapper knowledgeDocumentsMapper;
    @Resource
    private LLMBackendProperties llmBackendProperties;

    // 聊天会话历史记录缓存Key
    private final static String CHAT_HIStORY_REDIS_KEY = "llm:chat:history";
    // 聊天会话历史记录缓存时间
    private final static Long CHAT_HISTORY_REDIS_EXPIRE_SECONDS = 60 * 60 * 24L;

    @Override
    public Integer createConversation(ConversationSaveReqVO createReqVO) {
        // 插入
        ConversationDO conversation = BeanUtils.toBean(createReqVO, ConversationDO.class);
        conversationMapper.insert(conversation);
        // 返回
        return conversation.getId();
    }

    @Override
    public void updateConversation(ConversationSaveReqVO updateReqVO) {
        // 校验存在
        validateConversationExists(updateReqVO.getId());
        // 更新
        ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class);
        conversationMapper.updateById(updateObj);
    }

    @Override
    public void deleteConversation(Integer id) {
        // 校验存在
        validateConversationExists(id);
        // 删除
        conversationMapper.deleteById(id);
    }

    private void validateConversationExists(Integer id) {
        if (conversationMapper.selectById(id) == null) {
            throw exception(CONVERSATION_NOT_EXISTS);
        }
    }

    @Override
    public ConversationDO getConversation(Integer id) {
        return conversationMapper.selectById(id);
    }

    @Override
    public PageResult<ConversationDO> getConversationPage(ConversationPageReqVO pageReqVO) {
        return conversationMapper.selectPage(pageReqVO);
    }

    @Override
    public ChatRespVO chat(ChatReqVO chatReqVO) {
        if(chatReqVO.getSystemPrompt() == null || chatReqVO.getSystemPrompt().equals("")){
            if(chatReqVO.getApplicationId() != null){
                ApplicationRespVO application = applicationService.getApplication(chatReqVO.getApplicationId());
                List<String> messageHistoryList = stringRedisTemplate.opsForList().range(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), 0, -1);
                if (CollectionUtils.isEmpty(messageHistoryList)){
                    application.setChatCount(application.getChatCount() + 1);
                    ApplicationSaveReqVO applicationSaveReqVO = BeanUtils.toBean(application, ApplicationSaveReqVO.class);
                    applicationService.updateApplication(applicationSaveReqVO);
                }
                /*Long promptId = application.getPromptId();
                PromptTemplatesRespVO promptTemplates = promptTemplatesService.getPromptTemplates(promptId);
                if(promptTemplates != null){
                    chatReqVO.setSystemPrompt(promptTemplates.getTemplateText());
                }*/
                chatReqVO.setSystemPrompt(application.getPrompt());
            }
        }
      /*  if (Objects.equals(1, chatReqVO.getModelType())){
            return publicModelChat(chatReqVO);
        }else {
            return privateModelChat(chatReqVO);
        }*/
        return publicModelChat(chatReqVO);
    }

    @Override
    public JSONArray textToImage(TextToImageReqVo req) {
        TextToImageRespVo textToImageRespVo = modelService.textToImage(req);
        return textToImageRespVo.getData();
    }


    /**
     * 公共模型聊天
     * @param chatReqVO
     * @return
     */
    public ChatRespVO publicModelChat(ChatReqVO chatReqVO) {
        if (StringUtils.isBlank(chatReqVO.getUuid())) {
            // 如果没有uuid，就生成一个
            chatReqVO.setUuid(UUID.randomUUID().toString());
        }
        String model = null;
        if (Objects.equals(1, chatReqVO.getModelType())) {
            // 预制模型
            BaseModelDO baseModelDO = baseModelService.getBaseModel(chatReqVO.getModelId());
            if (baseModelDO == null) {
                throw exception(BASE_MODEL_NOT_EXISTS);
            }
            model = baseModelDO.getAigcModelName();
        }else if (Objects.equals(0, chatReqVO.getModelType())) {
            // 自定义模型
            ModelServiceDO modelServiceDO = modelServiceMapper.selectById(chatReqVO.getModelId());
            if (modelServiceDO == null) {
                throw exception(MODEL_SERVICE_NOT_EXISTS);
            }
            model = modelServiceDO.getBaseModelName();
        }else {
            throw exception(BASE_MODEL_NOT_EXISTS);
        }

        List<ModelCompletionsReqVO.ModelCompletionsMessage> messages = new ArrayList<>();

        //如果知识库id不为null，先去调用知识库
        StringBuilder  knowledgeBase = new StringBuilder();
        if(chatReqVO.getKnowledge() != null && chatReqVO.getKnowledge() != 0){
            LambdaQueryWrapper<KnowledgeDocumentsDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(KnowledgeDocumentsDO::getKnowledgeBaseId,chatReqVO.getKnowledge());
            List<KnowledgeDocumentsDO> fileList = knowledgeDocumentsMapper.selectList(queryWrapper);
            for (KnowledgeDocumentsDO knowledgeDocumentsDO : fileList) {
                Long id = knowledgeDocumentsDO.getId();
                KnowledgeRagEmbedQueryVO knowledgeRagEmbedQueryVO = new KnowledgeRagEmbedQueryVO();
                knowledgeRagEmbedQueryVO.setFile_id(id.toString());
                knowledgeRagEmbedQueryVO.setQuery(chatReqVO.getPrompt());
                String result = HttpUtils.post(llmBackendProperties.getEmbedQuery(), null, JSON.toJSONString(knowledgeRagEmbedQueryVO));
                com.alibaba.fastjson.JSONArray jsonArray = JSON.parseArray(result);
                if (jsonArray != null && !jsonArray.isEmpty()){
                    com.alibaba.fastjson.JSONArray jsonArray1 = (com.alibaba.fastjson.JSONArray) jsonArray.get(0);
                    JSONObject jsonObject = (JSONObject) jsonArray1.get(0);
                    knowledgeBase.append(jsonObject.get("page_content"));
                }
            }
        }
        String mess = chatReqVO.getSystemPrompt()+"<content>"+knowledgeBase.toString()+"</content>";
        // 查询历史记录消息 将查询出来的知识信息放入到 role = system 里面
        List<String> messageHistoryList = stringRedisTemplate.opsForList().range(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), 0, -1);
        if (messageHistoryList != null && !messageHistoryList.isEmpty()) {
            for (String messageHistory : messageHistoryList) {
                ModelCompletionsReqVO.ModelCompletionsMessage modelCompletionsMessage = JsonUtils.parseObject(messageHistory, ModelCompletionsReqVO.ModelCompletionsMessage.class);
                if (modelCompletionsMessage.getRole().equals("system")){
                    modelCompletionsMessage.setContent(mess);
                    stringRedisTemplate.opsForList().set(CHAT_HIStORY_REDIS_KEY+ ":" + chatReqVO.getUuid(), 0,  JsonUtils.toJsonString(modelCompletionsMessage));
                }
                messages.add(modelCompletionsMessage);
            }
        }else {
            ModelCompletionsReqVO.ModelCompletionsMessage systemMessage = new ModelCompletionsReqVO.ModelCompletionsMessage();
            systemMessage.setRole("system");
            systemMessage.setContent(mess);
            stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(systemMessage));
            messages.add(systemMessage);
        }
        // 先注释掉
/*        if(chatReqVO.getSystemPrompt() != null && !chatReqVO.getSystemPrompt().equals("")){
            ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage();
            message.setRole("system");
            message.setContent(mess);
            messages.add(message);
        }

        // TODO: 聊天推理
        List<String> messageHistoryList1 = stringRedisTemplate.opsForList().range(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), 0, -1);
        if (messageHistoryList1 != null && !messageHistoryList1.isEmpty()) {
            for (String messageHistory : messageHistoryList1) {
                messages.add(JsonUtils.parseObject(messageHistory, ModelCompletionsReqVO.ModelCompletionsMessage.class));
            }
        }*/




        ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage();
        message.setRole("user");
        message.setContent(chatReqVO.getPrompt());

        messages.add(message);

        ModelCompletionsReqVO modelCompletionsReqVO = new ModelCompletionsReqVO();
        modelCompletionsReqVO.setMessages(messages);
        // baseModel 的 aigcModelName 为aigc中的模型名称
        modelCompletionsReqVO.setModel(model);
        ModelCompletionsRespVO modelCompletionsRespVO = modelService.modelCompletions(modelCompletionsReqVO);
        if (modelCompletionsRespVO == null) {
            throw exception(MODEL_COMPLETIONS_ERROR);
        }
        ChatRespVO chatRespVO = BeanUtils.toBean(chatReqVO, ChatRespVO.class);
        chatRespVO.setResponse(modelCompletionsRespVO.getAnswer());
        // 将聊天记录放入缓存 先注释 TODO
        stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(message));
        ModelCompletionsReqVO.ModelCompletionsMessage responseMessage = new ModelCompletionsReqVO.ModelCompletionsMessage();
        responseMessage.setRole("assistant");
        responseMessage.setContent(modelCompletionsRespVO.getAnswer());
        stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(responseMessage));
        DataRefluxDataSaveReqVO dataRefluxDataSaveReqVO = new DataRefluxDataSaveReqVO();
        dataRefluxDataSaveReqVO.setModelServiceId(chatReqVO.getModelId());
        dataRefluxDataSaveReqVO.setModelType(chatReqVO.getModelType());
        dataRefluxDataSaveReqVO.setPrompt(chatReqVO.getPrompt());
        dataRefluxDataSaveReqVO.setResponse(modelCompletionsRespVO.getAnswer());
        dataRefluxDataSaveReqVO.setSystem(modelCompletionsRespVO.getSystem());
        dataRefluxDataService.saveDataRefluxData(dataRefluxDataSaveReqVO);
        return chatRespVO;
    }
    /**
     * 私有模型聊天
     * @param chatReqVO
     * @return
     */
    private ChatRespVO privateModelChat(ChatReqVO chatReqVO) {
        if (StringUtils.isBlank(chatReqVO.getUuid())) {
            // 如果没有uuid，就生成一个
            chatReqVO.setUuid(UUID.randomUUID().toString());
        }
        String model = null;
        if (Objects.equals(0, chatReqVO.getModelType())) {
            // 模型管理
            ModelServiceDO modelServiceDO = modelServiceMapper.selectById(chatReqVO.getModelId());
            if (modelServiceDO == null) {
                throw exception(MODEL_SERVICE_NOT_EXISTS);
            }
            model = modelServiceDO.getBaseModelName();
        }
        ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage();
        message.setRole("user");
        message.setContent(chatReqVO.getPrompt());

        List<String> messageHistoryList = stringRedisTemplate.opsForList().range(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), 0, -1);
        List<ModelCompletionsReqVO.ModelCompletionsMessage> messages = new ArrayList<>();
        if (messageHistoryList != null && !messageHistoryList.isEmpty()) {
            for (String messageHistory : messageHistoryList) {
                ModelCompletionsReqVO.ModelCompletionsMessage modelCompletionsMessage = JsonUtils.parseObject(messageHistory, ModelCompletionsReqVO.ModelCompletionsMessage.class);
                if (modelCompletionsMessage.getRole().equals("system")){
                    modelCompletionsMessage.setContent(StringUtils.isNotBlank(chatReqVO.getSystemPrompt())? chatReqVO.getSystemPrompt():"");
                    stringRedisTemplate.opsForList().set(CHAT_HIStORY_REDIS_KEY+ ":" + chatReqVO.getUuid(), 0,  JsonUtils.toJsonString(modelCompletionsMessage));
                }
                messages.add(modelCompletionsMessage);
            }
        }else {
            ModelCompletionsReqVO.ModelCompletionsMessage systemMessage = new ModelCompletionsReqVO.ModelCompletionsMessage();
            systemMessage.setRole("system");
            systemMessage.setContent(StringUtils.isNotBlank(chatReqVO.getSystemPrompt())? chatReqVO.getSystemPrompt():"");
            stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(systemMessage));
            messages.add(systemMessage);
        }
        messages.add(message);
        ModelCompletionsReqVO modelCompletionsReqVO = new ModelCompletionsReqVO();
        modelCompletionsReqVO.setMessages(messages);
        //         TODO 先传固定的内容  后期和后端调通直接修改成 model  1.23 已修改
        modelCompletionsReqVO.setModel(model);
        ModelCompletionsRespVO modelCompletionsRespVO = modelService.modelPrivateCompletions(new HashMap<>(),modelCompletionsReqVO);
        if (modelCompletionsRespVO == null) {
            throw exception(MODEL_COMPLETIONS_ERROR);
        }
        ChatRespVO chatRespVO = BeanUtils.toBean(chatReqVO, ChatRespVO.class);
        chatRespVO.setResponse(modelCompletionsRespVO.getAnswer());
        stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(message));
        ModelCompletionsReqVO.ModelCompletionsMessage responseMessage = new ModelCompletionsReqVO.ModelCompletionsMessage();
        responseMessage.setRole("assistant");
        responseMessage.setContent(modelCompletionsRespVO.getAnswer());
        stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(responseMessage));
        DataRefluxDataSaveReqVO dataRefluxDataSaveReqVO = new DataRefluxDataSaveReqVO();
        dataRefluxDataSaveReqVO.setModelServiceId(chatReqVO.getModelId());
        dataRefluxDataSaveReqVO.setModelType(chatReqVO.getModelType());
        dataRefluxDataSaveReqVO.setPrompt(chatReqVO.getPrompt());
        dataRefluxDataSaveReqVO.setResponse(modelCompletionsRespVO.getAnswer());
        dataRefluxDataSaveReqVO.setSystem(modelCompletionsRespVO.getSystem());
        dataRefluxDataService.saveDataRefluxData(dataRefluxDataSaveReqVO);
        return chatRespVO;
    }
}
