package com.supervision.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.supervision.config.domain.GlobalResult;
import com.supervision.domain.IrKnowledge;
import com.supervision.domain.IrKnowledgeSimilar;
import com.supervision.dto.matchTool.ExtractInformationDTO;
import com.supervision.dto.matchTool.MatchQuestionAnswerDTO;
import com.supervision.dto.matchTool.MatchToolQuestionDTO;
import com.supervision.dto.QuestionReqDTO;
import com.supervision.exception.BusinessException;
import com.supervision.service.IrKnowledgeService;
import com.supervision.service.IrKnowledgeSimilarService;
import com.supervision.service.MatchToolService;
import com.supervision.vo.matchTool.ExtractInformationReqVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class MatchToolServiceImpl implements MatchToolService {

    private final IrKnowledgeService irKnowledgeService;

    private final IrKnowledgeSimilarService irKnowledgeSimilarService;

    @Value("${matchTool.url}")
    private String matchToolUrl;

    @Value("${matchTool.scoreThreshold}")
    private String scoreThreshold;

    @Override
    public void refreshMatchToolLibrary() {
        // 获取所有的问题
        List<IrKnowledge> knowledgeList = irKnowledgeService.list();
        // 获取相似问题
        List<IrKnowledgeSimilar> similarList = irKnowledgeSimilarService.list();
        Map<String, List<IrKnowledgeSimilar>> similarKnowledgeMap = similarList.stream().collect(Collectors.groupingBy(IrKnowledgeSimilar::getKnowledgeId));
        Map<String, List<String>> questionLibrary = knowledgeList.stream().collect(Collectors.toMap(IrKnowledge::getId, e -> CollUtil.newArrayList(e.getStandardQuestion())));
        List<MatchToolQuestionDTO> matchToolQuestionDTOList = new ArrayList<>();

        for (Map.Entry<String, List<String>> entry : questionLibrary.entrySet()) {
            String questionId = entry.getKey();
            List<IrKnowledgeSimilar> similarKnowledgeList = similarKnowledgeMap.get(questionId);
            if (CollUtil.isNotEmpty(similarKnowledgeList)) {
                Set<String> similarQuestionSet = similarKnowledgeList.stream().map(IrKnowledgeSimilar::getSimilarQuestion).collect(Collectors.toSet());
                entry.getValue().addAll(similarQuestionSet);
            }
            MatchToolQuestionDTO matchToolQuestionDTO = new MatchToolQuestionDTO();
            matchToolQuestionDTO.setQuestionId(questionId);
            matchToolQuestionDTO.setQuestionList(entry.getValue());
            matchToolQuestionDTOList.add(matchToolQuestionDTO);
        }
        // 调用tool服务进行更新操作
        submitRefresh(matchToolQuestionDTOList);
        // 更新完成之后,将数据置为生效
        irKnowledgeService.lambdaUpdate().set(IrKnowledge::getState, 1).in(IrKnowledge::getId, questionLibrary.keySet()).update();
        Set<String> similarKnowledgeIdSet = similarList.stream().map(IrKnowledgeSimilar::getId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(similarKnowledgeIdSet)) {
            irKnowledgeSimilarService.lambdaUpdate().set(IrKnowledgeSimilar::getState, 1).in(IrKnowledgeSimilar::getId, similarKnowledgeIdSet).update();
        }
    }

    @Override
    public List<MatchQuestionAnswerDTO> execMatch(String question) {
        log.info("开始调用talkQaSimilarity,问题:{}", question);
        try {
            // 清洗数据，去除句子中的字母和数字，以提高相似度
            question = StrUtil.replace(question, "[a-zA-Z0-9\\s+]", m->"");
            log.info("经过去除字母和数字清洗后的字符串是:{}",question);
            TimeInterval timer = DateUtil.timer();
            String post = HttpUtil.post(matchToolUrl + "/matchQuestion", JSONUtil.toJsonStr(new QuestionReqDTO(question, Double.valueOf(scoreThreshold))));
            log.info("相似度匹配答案:{},耗时:{} 毫秒", post,timer.intervalMs());
            TypeReference<GlobalResult<List<MatchQuestionAnswerDTO>>> globalResultTypeReference = new TypeReference<GlobalResult<List<MatchQuestionAnswerDTO>>>() {
            };
            GlobalResult<List<MatchQuestionAnswerDTO>> result = JSONUtil.toBean(post, globalResultTypeReference.getType(), true);
            if (result.getCode() != 200) {
                throw new BusinessException("匹配失败");
            }
            List<MatchQuestionAnswerDTO> data = result.getData();
            if (CollUtil.isEmpty(data)){
                throw new BusinessException("未识别的问题");
            }
            return data;
        } catch (Exception e) {
            log.error("调用talkQaSimilarity error ", e);
            return null;
        }
    }
    @Override
    public ExtractInformationDTO extractInformation(String message) {
        log.info("开始调用extractInformation,message:{}", message);
        if (StrUtil.isEmpty(message)) {
            return null;
        }
        try {
            TimeInterval timer = DateUtil.timer();
            String result = HttpUtil.post(matchToolUrl + "/extractInformation", JSONUtil.toJsonStr(new ExtractInformationReqVo(message)));
            log.info("抽取信息message:{}抽取结果:{},耗时:{} 毫秒", message, result, timer.intervalMs());
            TypeReference<ExtractInformationDTO> globalResultTypeReference = new TypeReference<ExtractInformationDTO>() {
            };
            return JSONUtil.toBean(result, globalResultTypeReference.getType(), true);
        } catch (Exception e) {
            log.error("调用extractInformation error ", e);
            return null;
        }
    }

    private void submitRefresh(List<MatchToolQuestionDTO> matchToolQuestionDTOList) {
        log.info("开始调用matchTool服务进行更新操作");
        try {
            String post = HttpUtil.post(matchToolUrl + "/updateDatabase", JSONUtil.toJsonStr(matchToolQuestionDTOList));
            log.info(post);
            if (!JSONUtil.isTypeJSON(post)) {
                throw new BusinessException("更新失败");
            }
        } catch (Exception e) {
            log.error("调用matchTool服务更新失败", e);
            throw new BusinessException("更新失败");
        }
        log.info("成功调用matchTool服务更新数据库");


    }


}
