package com.zzsn.knowbase.task;

import com.alibaba.fastjson.JSON;
import com.zzsn.knowbase.constant.Constants;
import com.zzsn.knowbase.entity.Content;
import com.zzsn.knowbase.entity.KbKnowledges;
import com.zzsn.knowbase.entity.Knowledge;
import com.zzsn.knowbase.entity.subject.IntelligenceInfo;
import com.zzsn.knowbase.kafka.message.KnowledgeMessage;
import com.zzsn.knowbase.kafka.producer.ProduceInfo;
import com.zzsn.knowbase.service.IKnowledgeService;
import com.zzsn.knowbase.service.KbKnowledgesService;
import com.zzsn.knowbase.util.*;
import com.zzsn.knowbase.vo.KnowledgeVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 *  同步专题数据到知识库
 */
@Slf4j
@RestController
@RequestMapping("subjectDataSyncTask")
public class SubjectDataSyncTask {
	@Autowired
	private KbKnowledgesService kbKnowledgesService;
	@Autowired
	private IKnowledgeService knowledgeService;
	@Autowired
	private EsOpUtil esOpUtil;
	@Autowired
	private CodeGenerateUtil codeGenerateUtil;
	@Autowired
	private ProduceInfo produceInfo;

	@Scheduled(cron = "0 */10 * * * ?")
	public void startTask() {
		manualRunTask(null,null,null);
	}

	/**
	 * 任务开始执行
	 * @param syncStart 更新时间-开始
	 * @param syncEnd 更新时间-结束
	 * @param knowId 知识库id
	 */
	@GetMapping("manualRunTask")
	public void manualRunTask(String syncStart,String syncEnd,String knowId) {
		if(StringUtils.isNotEmpty(knowId)){
			KbKnowledges byId = kbKnowledgesService.getById(knowId);
			byId.setSyncStart(syncStart);
			byId.setSyncEnd(syncEnd);
			sync(byId);
		}else{
			List<KbKnowledges> confList = kbKnowledgesService.syncSubjectConf();
			for (KbKnowledges kbKnowledges : confList) {
				kbKnowledges.setSyncStart(syncStart);
				kbKnowledges.setSyncEnd(syncEnd);
				sync(kbKnowledges);
			}
		}
	}
	public void sync(KbKnowledges kbKnowledges) {
		//按审核状态分组
		Map<Integer, List<String>> checkStatusMap = new HashMap<>();
		//提取发布状态分组
		Map<Integer, List<String>> publishStatusMap = new HashMap<>();
		//已删除数据
		List<String> deleteList = new ArrayList<>();
		getSubjectIdGroup(kbKnowledges,checkStatusMap,publishStatusMap,deleteList);
		//根据专题配置，提取有效数据
		List<String> subjectValidList1 = new ArrayList<>();
		List<String> subjectValidList2 = new ArrayList<>();
		if(StringUtils.isNotEmpty(kbKnowledges.getSubjectStatus())){
			String subjectStatus = kbKnowledges.getSubjectStatus();
			for (String status : subjectStatus.split(",")) {
				if(checkStatusMap.get(Integer.parseInt(status)) != null){
					subjectValidList1.addAll(checkStatusMap.get(Integer.parseInt(status)));
				}
			}
		}else{
			for (Map.Entry<Integer, List<String>> entry : checkStatusMap.entrySet()) {
				subjectValidList1.addAll(entry.getValue());
			}
		}

		if(StringUtils.isNotEmpty(kbKnowledges.getSubjectPublishStatus())){
			String subjectStatus = kbKnowledges.getSubjectPublishStatus();
			for (String status : subjectStatus.split(",")) {
				if(publishStatusMap.get(Integer.parseInt(status)) != null){
					subjectValidList2.addAll(publishStatusMap.get(Integer.parseInt(status)));
				}
			}
		}else{
			for (Map.Entry<Integer, List<String>> entry : publishStatusMap.entrySet()) {
				subjectValidList2.addAll(entry.getValue());
			}
		}
		//专题有效数据 (交集)
		List<String> subjectValidList = new ArrayList<>(subjectValidList1);
		subjectValidList.retainAll(subjectValidList2);

		//知识库有效数据
		List<String> knowValidList = new ArrayList<>();
		//知识库删除数据
		List<String> knowDeleteList = new ArrayList<>();
		getKnowId(kbKnowledges,knowValidList,knowDeleteList);

		//待删除数据id
		List<String> hasDeleteList = new ArrayList<>();
		//待新增数据id
		List<String> hasAddList = new ArrayList<>();
		if(!subjectValidList.isEmpty()){
			//提取需要新增或更新的数据
			hasAddList = new ArrayList<>(subjectValidList);
			hasAddList.removeAll(knowValidList);
		}
		if(!knowValidList.isEmpty()){
			//提取需要删除的数据（知识库存在有效数据，专题库非配置状态范围内数据）
			hasDeleteList = new ArrayList<>(knowValidList);
			hasDeleteList.removeAll(subjectValidList);
			//本次更新数据不需要删除
			hasDeleteList.removeAll(hasAddList);
		}
		log.info("知识库：{}，需要新增或更新的数据：{}",kbKnowledges.getName(),hasAddList);
		log.info("知识库：{}，需要删除的数据：{}",kbKnowledges.getName(),hasDeleteList);
		//处理待修改数据
		for (String item : hasAddList) {
			String id = item.split(",")[0];
			Map<String, Object> mapItem = esOpUtil.searchDoc(Constants.ES_SUBJECT_DATA, id);
			IntelligenceInfo subjectItem = JSON.parseObject(JSON.toJSONString(mapItem), IntelligenceInfo.class);
			Knowledge knowledge = new Knowledge();
			knowledge.setUpdateDate(subjectItem.getUpdateDate());
			knowledge.setPublishDate(subjectItem.getPublishDate());
			knowledge.setAuthor(subjectItem.getAuthor());
			knowledge.setContentWithTag(subjectItem.getContentWithTag());
			knowledge.setId(id);
			knowledge.setDeleteFlag(0);
			knowledge.setCreateTime(EsDateUtil.esFieldDateFormat(cn.hutool.core.date.DateUtil.formatDateTime(new Date())));
			knowledge.setTitle(subjectItem.getTitle());
			knowledge.setSubjectId(kbKnowledges.getSubjectId());
			knowledge.setVerifyStatus(1);
			knowledge.setOrigin(subjectItem.getOrigin());
			knowledge.setSourceAddress(subjectItem.getSourceAddress());
			knowledge.setKbKnowledgeId(getId(kbKnowledges));
			knowledge.setKnowledgeProjectId(kbKnowledges.getProjectId());
			knowledge.setType("专题数据");
			knowledge.setTypeId(kbKnowledges.getTypeId());
			knowledge.setImportData(1);

			//片段切分
			List<Content> contents = new ArrayList<>();
			List<String> splitContents = HtmlUtil.splitContents(subjectItem.getContentWithTag());
			for (String content : splitContents) {
				System.out.println(content.length());
				System.out.println(content);
				contents.add(Content.builder()
						.contentId(codeGenerateUtil.geneIdNo(Constants.FINANCE, 8))
						.content(content)
						.build());
			}
			knowledge.setContents(contents);
			//判断是否存在
			if(esOpUtil.docExists(Constants.ES_DATA_FOR_KNOWLEDGE, id)){
				//更新数据
				esOpUtil.docUpdateById(Constants.ES_DATA_FOR_KNOWLEDGE, id, JSON.toJSONString(knowledge));
				log.info("知识库数据更新id：{},title：{}",knowledge.getId(),knowledge.getTitle());
				//删除向量库已有数据
				knowledgeService.deleteForPython(id, kbKnowledges.getId());
			}else {
				//添加数据
				esOpUtil.docSaveByJson(Constants.ES_DATA_FOR_KNOWLEDGE, id, JSON.toJSONString(knowledge));
				log.info("知识库数据新增id：{},title：{}",knowledge.getId(),knowledge.getTitle());
			}
			//通过kafka同步到向量库
			KnowledgeMessage knowledgeMessage = new KnowledgeMessage();
			BeanUtils.copyProperties(knowledge, knowledgeMessage);
			knowledgeMessage.setType(knowledge.getTypeId());
			produceInfo.sendKnowledgeContents(knowledgeMessage);
			log.info("通过kafka同步到向量库id：{},title：{}",knowledge.getId(),knowledge.getTitle());
		}
		//处理待删除数据
		for (String item : hasDeleteList) {
			String id = item.split(",")[0];
			//标记删除
			Knowledge knowledge = new Knowledge();
			knowledge.setId(id);
			knowledge.setDeleteFlag(1);
			esOpUtil.docUpdateById(Constants.ES_DATA_FOR_KNOWLEDGE, id, JSON.toJSONString(knowledge));
			knowledgeService.deleteForPython(id, kbKnowledges.getId());
			log.info("知识库数据删除id：{}",knowledge.getId());
		}
	}

	private static String getId(KbKnowledges kbKnowledges) {
		return kbKnowledges.getId();
	}

	public void getSubjectIdGroup(KbKnowledges kbKnowledges, Map<Integer, List<String>> checkStatusMap, Map<Integer, List<String>> publishStatusMap, List<String> deleteList) {
		//查询待同步数据id
		BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
		boolQuery.must(QueryBuilders.termsQuery("subjectId", kbKnowledges.getSubjectId().split(",")));
		if(StringUtils.isNotEmpty(kbKnowledges.getSyncStart())){
			boolQuery.filter(QueryBuilders.rangeQuery("updateDate").gte(kbKnowledges.getSyncStart()));
		}else{
			//只查询更新时间在最近一周的数据
			boolQuery.filter(QueryBuilders.rangeQuery("updateDate").gte(DateUtil.getStringDate(new Date(System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000L))));
		}
		if(StringUtils.isNotEmpty(kbKnowledges.getSyncEnd())){
			boolQuery.filter(QueryBuilders.rangeQuery("updateDate").lte(kbKnowledges.getSyncEnd()));
		}
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		//更新时间倒序
		searchSourceBuilder.sort("updateDate", SortOrder.DESC);
		searchSourceBuilder.trackTotalHits(true);
		searchSourceBuilder.query(boolQuery);
		//查询指定字段
		searchSourceBuilder.fetchSource(new String[]{"id","deleteFlag","checkStatus","publishStatus","updateDate"}, null);
		Map<String, Object> map = esOpUtil.searchByQuery(Constants.ES_SUBJECT_DATA ,
				0, 100000, searchSourceBuilder);
		List<Map<String, Object>> list = (List<Map<String, Object>>) map.get("data");
		if(list != null && !list.isEmpty()) {
			//分组提取id列表
			for (Map<String, Object> mapItem : list) {
				Object deleteFlag = mapItem.get("deleteFlag");
				if(deleteFlag != null && "1".equals(deleteFlag.toString())){
					//已删除数据
					deleteList.add(mapItem.get("id").toString()+","+mapItem.get("updateDate").toString());
					continue;
				}
				groupMap(checkStatusMap, mapItem, mapItem.get("checkStatus"));
				groupMap(publishStatusMap, mapItem, mapItem.get("publishStatus"));
			}
		}
	}
	public void getKnowId(KbKnowledges kbKnowledges, List<String> validList, List<String> deleteList) {
		//查询待同步数据id
		BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
		boolQuery.must(QueryBuilders.termsQuery("subjectId", kbKnowledges.getSubjectId().split(",")));
		//只查询更新时间在最近一周的数据
		if(StringUtils.isNotEmpty(kbKnowledges.getSyncStart())){
			boolQuery.filter(QueryBuilders.rangeQuery("updateDate").gte(kbKnowledges.getSyncStart()));
		}else{
			//只查询更新时间在最近一周的数据
			boolQuery.filter(QueryBuilders.rangeQuery("updateDate").gte(DateUtil.getStringDate(new Date(System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000L))));
		}
		if(StringUtils.isNotEmpty(kbKnowledges.getSyncEnd())){
			boolQuery.filter(QueryBuilders.rangeQuery("updateDate").lte(kbKnowledges.getSyncEnd()));
		}
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		//更新时间倒序
		searchSourceBuilder.sort("updateDate", SortOrder.DESC);
		searchSourceBuilder.trackTotalHits(true);
		searchSourceBuilder.query(boolQuery);
		//查询指定字段
		searchSourceBuilder.fetchSource(new String[]{"id","deleteFlag","verifyStatus","updateDate"}, null);
		Map<String, Object> map = esOpUtil.searchByQuery(Constants.ES_DATA_FOR_KNOWLEDGE ,
				0, 100000, searchSourceBuilder);
		List<Map<String, Object>> list = (List<Map<String, Object>>) map.get("data");
		if(list != null || !list.isEmpty()) {
			//分组提取id列表
			for (Map<String, Object> mapItem : list) {
				Object deleteFlag = mapItem.get("deleteFlag");
				if(deleteFlag != null && "1".equals(deleteFlag.toString())){
					//已删除数据
					deleteList.add(mapItem.get("id").toString()+","+mapItem.get("updateDate").toString());
				}else{
					//只要未删除，均为有效数据
					validList.add(mapItem.get("id").toString()+","+mapItem.get("updateDate").toString());
				}
			}
		}
	}

	private void groupMap(Map<Integer, List<String>> statusMap, Map<String, Object> mapItem, Object status) {
		if(status == null){
			status = 0;
		}
		Integer statusInt = Integer.valueOf(status.toString());
		if(statusMap.containsKey(statusInt)){
			statusMap.get(statusInt).add(mapItem.get("id").toString()+","+mapItem.get("updateDate").toString());
		}else{
			List<String> tempList = new ArrayList<>();
			tempList.add(mapItem.get("id").toString()+","+mapItem.get("updateDate").toString());
			statusMap.put(statusInt,tempList);
		}
	}
}
