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

import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.llm.controller.admin.dataset.vo.DatasetAnswerRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.dataset.vo.DatasetQuestionRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelassesstaskauto.vo.ModelAssessTaskStoplistSaveReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelassesstaskmanual.vo.ModelAssessTaskManualSaveReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelassesstaskmanualbackup.vo.ModelAssessTaskManualBackupSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskauto.ModelAssessTaskAutoDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskautoinfo.ModelAssessTaskAutoInfoDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskmanual.ManualModelAnswerDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskmanual.ModelAssessTaskDimensionDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskmanual.ModelAssessTaskManualDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskmanualbackup.ManualModelAnswerBackupDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskmanualbackup.ModelAssessTaskDimensionBackupDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelassesstaskmanualbackup.ModelAssessTaskManualBackupDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO;
import cn.iocoder.yudao.module.llm.dal.mysql.basemodel.BaseModelMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.dataset.DatasetMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskauto.ModelAssessTaskAutoMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskautoinfo.ModelAssessTaskAutoInfoMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskmanual.ManualModelAnswerMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskmanual.ModelAssessTaskDimensionMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskmanual.ModelAssessTaskManualMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskmanualbackup.ManualModelAnswerBackupMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelassesstaskmanualbackup.ModelAssessTaskDimensionBackupMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.service.conversation.ConversationService;
import cn.iocoder.yudao.module.llm.service.dataset.DatasetQuestionService;
import cn.iocoder.yudao.module.llm.service.http.ModelService;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.http.vo.ModelCompletionsReqVO;
import cn.iocoder.yudao.module.llm.service.http.vo.ModelCompletionsRespVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.engine.constraintvalidation.PredefinedScopeConstraintValidatorManagerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class AsyncModelAccessManualService {
    private static final Logger log = LoggerFactory.getLogger(AsyncModelAccessManualService.class);
    @Resource
    private ModelService modelService;
    @Resource
    private DatasetQuestionService datasetQuestionService;
    @Resource
    private ManualModelAnswerMapper manualModelAnswerMapper;
    @Resource
    private ModelAssessTaskManualMapper modelAssessTaskManualMapper;
    @Resource
    private ModelAssessTaskDimensionMapper modelAssessTaskDimensionMapper;
    @Resource
    private ModelAssessTaskDimensionBackupMapper modelAssessTaskDimensionBackupMapper;
    @Resource
    private ManualModelAnswerBackupMapper manualModelAnswerBackupMapper;
    @Resource
    private ModelAssessTaskAutoMapper modelAssessTaskAutoMapper;
    @Resource
    private TrainHttpService trainHttpService;
    @Resource
    private ModelServiceMapper modelServiceMapper;
    @Resource
    private BaseModelMapper baseModelMapper;
    @Resource
    private ModelAssessTaskAutoInfoMapper modelAssessTaskAutoInfoMapper;


    @Async
    public void auto(ModelAssessTaskAutoDO modelAssessTaskAuto,List<ModelAssessTaskStoplistSaveReqVO> stoplists) {
        try {
            List<DatasetQuestionRespVO> datasetQuestionList = datasetQuestionService.getDatasetQuestionList(modelAssessTaskAuto.getDataset());
            for (DatasetQuestionRespVO datasetQuestionRespVO : datasetQuestionList) {
                String question = datasetQuestionRespVO.getQuestion();
                DatasetAnswerRespVO datasetAnswerRespVO = datasetQuestionRespVO.getDatasetAnswerRespVO().get(0);
                String datasetPrompt = datasetAnswerRespVO.getAnswer();

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

                if(stoplists != null && stoplists.size() > 0){
                    String stoplistsStr = Joiner.on(",").join(stoplists);
                    ModelCompletionsReqVO.ModelCompletionsMessage system = new ModelCompletionsReqVO.ModelCompletionsMessage();
                    system.setRole("system");
                    system.setContent("不要出现以下停用词:" + stoplistsStr);
                    messages.add(system);
                }

                ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage();
                if (question != null){
                    message.setContent(question);
                }
                message.setRole("user");
                messages.add(message);

                String modelName = "";
                if(modelAssessTaskAuto.getModelType() == 0){
                    ModelServiceDO modelServiceDO = modelServiceMapper.selectById(modelAssessTaskAuto.getModelService());
                    if (modelServiceDO != null){
                         modelName = modelServiceDO.getBaseModelName();
                    }
                }else{
                    BaseModelDO baseModelDO = baseModelMapper.selectById(modelAssessTaskAuto.getModelService());
                    if (baseModelDO != null){
                        modelName = baseModelDO.getModelName();
                    }
                }

                ModelCompletionsReqVO modelCompletionsReqVO = new ModelCompletionsReqVO();
                modelCompletionsReqVO.setMessages(messages);
                modelCompletionsReqVO.setModel(modelName);
                ModelCompletionsRespVO modelCompletionsRespVO = modelService.modelCompletions(modelCompletionsReqVO);
                String prompt = modelCompletionsRespVO.getAnswer();
                String res = trainHttpService.autoEvaluation(prompt, datasetPrompt);

                ModelAssessTaskAutoInfoDO infoDO = new ModelAssessTaskAutoInfoDO();
                infoDO.setPrompt(prompt);
                infoDO.setDataSetPrompt(datasetPrompt);
                infoDO.setQuestion(question);

                infoDO.setTaskId(modelAssessTaskAuto.getId());
                infoDO.setModelName(modelName);

                String[] split = res.split("\n");
                List<String> list = new ArrayList<>(Arrays.asList(split));
                if(list.size() < 3){
                    if(res.contains("good")){
                        infoDO.setEmotionTendency(2);
                        infoDO.setFactualError(2);
                        infoDO.setSemanticsCoherence(2);
                    }else if(res.contains("same")){
                        infoDO.setEmotionTendency(1);
                        infoDO.setFactualError(1);
                        infoDO.setSemanticsCoherence(1);
                    }else if(res.contains("bad")){
                        infoDO.setEmotionTendency(0);
                        infoDO.setFactualError(0);
                        infoDO.setSemanticsCoherence(0);
                    }
                }else{
                    for (String s : list) {
                        if(s.contains("事实性错误")){
                            if(s.contains("good")){
                                infoDO.setFactualError(2);
                            }else if (s.contains("same")){
                                infoDO.setFactualError(1);
                            }else if (s.contains("bad")){
                                infoDO.setFactualError(0);
                            };
                        }else if(s.contains("事实性错误")){
                            if(s.contains("good")){
                                infoDO.setSemanticsCoherence(2);
                            }else if (s.contains("same")){
                                infoDO.setSemanticsCoherence(1);
                            }else if (s.contains("bad")){
                                infoDO.setSemanticsCoherence(0);
                            };
                        }else if(s.contains("情感倾向性")){
                            if(s.contains("good")){
                                infoDO.setEmotionTendency(2);
                            }else if (s.contains("same")){
                                infoDO.setEmotionTendency(1);
                            }else if (s.contains("bad")){
                                infoDO.setEmotionTendency(0);
                            };
                        }
                    }
                }
                //评估结果: \n\n- 事实性错误: bad\n- 情感倾向性: same\n- 语义连贯性: same
                //评估结果: \n- 事实性错误: bad\n- 情感倾向性: same\n- 语义连贯性: good
                //事实性错误: bad  \n情感倾向性: same  \n语义连贯性: bad
                //评估结果: good
                modelAssessTaskAutoInfoMapper.insert(infoDO);
            }

            modelAssessTaskAuto.setStatus(4);
            modelAssessTaskAutoMapper.updateById(modelAssessTaskAuto);
        }catch (Exception e){
            log.error("autoTask error : {}",e.getMessage());
            modelAssessTaskAuto.setStatus(5);
            modelAssessTaskAutoMapper.updateById(modelAssessTaskAuto);
        }


    }

    @Async
    public void startModelAccess(ModelAssessTaskManualDO task) {
        List<DatasetQuestionRespVO> datasetQuestionList = datasetQuestionService.getDatasetQuestionList(task.getDataset());
        try {
            if (!CollectionUtils.isAnyEmpty(datasetQuestionList)){
                String modelName;
                if (task.getModelType()==1){
                    BaseModelDO baseModelDO = baseModelMapper.selectById(task.getModelService());
                    if (baseModelDO != null){
                        modelName = baseModelDO.getAigcModelName();
                    } else {
                        modelName = "";
                    }
                } else {
                    ModelServiceDO modelServiceDO = modelServiceMapper.selectById(task.getModelService());
                    if (modelServiceDO != null){
                        modelName = modelServiceDO.getBaseModelName();
                    } else {
                        modelName = "";
                    }
                }
                datasetQuestionList.forEach(item -> {
                    ModelCompletionsReqVO modelCompletionsReqVO = new ModelCompletionsReqVO();
                    modelCompletionsReqVO.setModel(modelName);
                    ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage();
                    if (item.getQuestion() != null){
                        message.setContent(item.getQuestion());
                    }
                    message.setRole("user");
                    List<ModelCompletionsReqVO.ModelCompletionsMessage> messages = new ArrayList<>();
                    messages.add(message);
                    modelCompletionsReqVO.setMessages(messages);
                    ModelCompletionsRespVO modelCompletionsRespVO = modelService.modelCompletions(modelCompletionsReqVO);
                    if (modelCompletionsRespVO != null){
                        ManualModelAnswerDO manualModelAnswerDO = new ManualModelAnswerDO();
                        manualModelAnswerDO.setCreator(task.getCreator());
                        manualModelAnswerDO.setUpdater(task.getCreator());
                        manualModelAnswerDO.setQuestionId(item.getId());
                        manualModelAnswerDO.setModelAnswer(modelCompletionsRespVO.getAnswer());
                        manualModelAnswerDO.setManalTaskId(task.getId());
                        manualModelAnswerDO.setDatasetId(task.getDataset());
                        manualModelAnswerMapper.insert(manualModelAnswerDO);
                    }
                });
                task.setStatus(1);
                modelAssessTaskManualMapper.updateById(task);
            }
        }catch (Exception e){
            log.error("Model evaluation failed manually : {}",e.getMessage());
            task.setStatus(5);
            modelAssessTaskManualMapper.updateById(task);
        }

    }

    @Async
    public void manualBackup(ModelAssessTaskManualBackupDO backupDo) {
        try {
            // 源数据表
            Long srcId = backupDo.getSrcId();
            // 备份人工打分评估维度
            List<ModelAssessTaskDimensionDO> modelAssessTaskDimensionDOS = modelAssessTaskDimensionMapper.selectList(new LambdaQueryWrapper<ModelAssessTaskDimensionDO>()
                    .eq(ModelAssessTaskDimensionDO::getTaskId, srcId));
            if (!CollectionUtils.isAnyEmpty(modelAssessTaskDimensionDOS)){
                modelAssessTaskDimensionDOS.forEach(item -> {
                    ModelAssessTaskDimensionBackupDO bean = BeanUtils.toBean(item, ModelAssessTaskDimensionBackupDO.class);
                    bean.setId(null);
                    bean.setTaskId(backupDo.getId());
                    modelAssessTaskDimensionBackupMapper.insert(bean);
                });
            }
            List<ManualModelAnswerDO> manualModelAnswerDOS = manualModelAnswerMapper.selectList(new LambdaQueryWrapper<ManualModelAnswerDO>()
                    .eq(ManualModelAnswerDO::getManalTaskId, srcId));
            if (!CollectionUtils.isAnyEmpty(manualModelAnswerDOS)){
                manualModelAnswerDOS.forEach(item -> {
                    ManualModelAnswerBackupDO bean = BeanUtils.toBean(item, ManualModelAnswerBackupDO.class);
                    bean.setId(null);
                    bean.setManalTaskId(backupDo.getId());
                    manualModelAnswerBackupMapper.insert(bean);
                });
            }


        }catch (Exception e){
            log.error("Manual backup failed manually : {}",e.getMessage());
        }

    }
}
