package com.yeejoin.amos.boot.module.tzs.biz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.module.tzs.api.dto.AlertCalledDto;
import com.yeejoin.amos.boot.module.tzs.api.dto.ESAlertCalledDto;
import com.yeejoin.amos.boot.module.tzs.api.dto.ESAlertCalledRequestDto;
import com.yeejoin.amos.boot.module.tzs.api.entity.AlertCalled;
import com.yeejoin.amos.boot.module.tzs.api.entity.ESAlertCalled;
import com.yeejoin.amos.boot.module.tzs.api.enums.AlertStatusEnum;
import com.yeejoin.amos.boot.module.tzs.biz.dao.ESAlertCalledRepository;
import com.yeejoin.amos.boot.module.tzs.biz.utils.BeanDtoVoUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * <pre>
 * 警情信息ES检索服务
 * </pre>
 *
 * @author gwb
 * @version $Id: ESAlertCalledService.java, v 0.1 2021年6月19日 下午5:12:01 gwb Exp $
 */
@Service
public class ESAlertCalledService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;

    @Autowired
    private ESAlertCalledRepository esAlertCalledRepository;

	@Autowired
	private AlertCalledServiceImpl alertCalledService;

    @Value("${alertcall.es.synchrony.time}")
	private Long time;
    
    
	@PostConstruct
	public void init() throws Exception
	{
		//初始化ES，重建索引
		initEs();
	}

    /**
     * 重建索引
     */
    public Boolean initEs() throws Exception {
        esAlertCalledRepository.deleteAll();
        /**
         * 同步历史48小时以内的警情处置记录
         */
        QueryWrapper<AlertCalled> wrapper = new QueryWrapper<>();

        long currentTime = System.currentTimeMillis() ;
        if (ValidationUtil.isEmpty(time)) //默认为同步48小时
		{
        	currentTime = currentTime - 48*60*60*1000;
		}else 
		{
			currentTime = currentTime - time*60*60*1000;
		}
        Date date=new Date(currentTime);

        wrapper.ge("call_time", date);

        List<AlertCalled> alertCalleds = alertCalledService.list(wrapper);
        if (!ValidationUtil.isEmpty(alertCalleds))
		{
    		for (AlertCalled alertCalled : alertCalleds)
    		{
    			saveAlertCalledToES(alertCalled);
    		}
		}
        return true;
    }


    /**
     *
     * <pre>
     * 根据警情记录批量保存
     * </pre>
     *
     * @param alertCalled 警情信息列表
     */
    public ESAlertCalled saveAlertCalledToES(AlertCalled alertCalled) throws Exception
    {
    	ESAlertCalled esAlertCalled = new ESAlertCalled();
    	esAlertCalled.setSequenceNbr(alertCalled.getSequenceNbr());
    	esAlertCalled.setAlarmType(alertCalled.getAlarmType());
    	esAlertCalled.setAlarmTypeCode(alertCalled.getAlarmTypeCode());
    	esAlertCalled.setCallTime(alertCalled.getCallTime());
    	esAlertCalled.setCallTimeLong(alertCalled.getCallTime()!=null?alertCalled.getCallTime().getTime():null);
    	esAlertCalled.setContactPhone(alertCalled.getContactPhone());
    	esAlertCalled.setAddress(alertCalled.getAddress());
    	esAlertCalled.setAlertStage(alertCalled.getAlertStage());
    	esAlertCalled.setAlertStatus(alertCalled.getAlertStatus());
		esAlertCalled.setEmergencyCall(alertCalled.getEmergencyCall());
		esAlertCalled.setDeviceId(alertCalled.getDeviceId());
		esAlertCalled.setUseUnit(alertCalled.getUseUnit());
    	if (alertCalled.getAlertStatus())
    	{
    		esAlertCalled.setAlertStatusStr(AlertStatusEnum.CLOSED.getCode());
    	}else
    	{
    		esAlertCalled.setAlertStatusStr(AlertStatusEnum.UNCLOSED.getCode());
    	}

    	esAlertCalledRepository.save(esAlertCalled);

    	return esAlertCalled;
    }

    /**
     * 根据关键字查询文档，关键字不为空时按相关性从大到小排序
     *
     * @param alertCalledVo 关键字
     * @param current  当前页码
     * @param size     页面大小
     * @return
     */
    @SuppressWarnings({ "rawtypes" })
	public Page<ESAlertCalledDto> queryByKeys(ESAlertCalledRequestDto alertCalledVo, int current, int size)
    {
    	Page<ESAlertCalledDto> result = new Page<ESAlertCalledDto>(current, size);
    	String[] alertStatus = alertCalledVo.getAlertStatus();
    	if (ValidationUtil.isEmpty(alertStatus))
		{
    		return result;
		}
    	AlertCalled alertCalled = BeanDtoVoUtils.convert(alertCalledVo.getAlertCalledDto(),AlertCalled.class);
    	if (ValidationUtil.isEmpty(alertCalled))
		{
			return result;
		}
        /**
         * 通用匹配规则，条件构建
         */
    	BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
		//警情状态
		BoolQueryBuilder qbstatus = QueryBuilders.boolQuery();
		for (String status : alertStatus)
		{
			AlertStatusEnum alertStatusEnum = AlertStatusEnum.getEnum(status);
			if (!ValidationUtil.isEmpty(alertStatusEnum))
			{
				qbstatus.should(QueryBuilders.termQuery("alertStatusStr", alertStatusEnum.getCode()));
			}
		}
		boolMust.must(qbstatus);
		// 如果没有搜索条件不搜索
		boolean flag = true;
		// ①事发地点一致，或相距不超过200米的；&& ②警情类别一致；&&  ③报警时间：距离当前时间不超过两小时的
		if (!ValidationUtil.isEmpty(alertCalled.getAddress()) && !ValidationUtil.isEmpty(alertCalled.getAlarmTypeCode()) && !ValidationUtil.isEmpty(alertCalled.getAlarmTypeCode()))
		{
			flag = false;
			BoolQueryBuilder qb0 = QueryBuilders.boolQuery();
			BoolQueryBuilder temp1 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.matchQuery("address", alertCalled.getAddress()));
			qb0.must(temp1);

			BoolQueryBuilder temp2 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.matchQuery("alarmTypeCode", alertCalled.getAlarmTypeCode()));
			qb0.must(temp2);

			//接警时间，距离当前时间不超过两个小时的
			long currentTime = System.currentTimeMillis() ;
			currentTime = currentTime - 120*60*1000;
			BoolQueryBuilder temp3 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.rangeQuery("callTimeLong").gte(currentTime));
			qb0.must(temp3);

			boolMust.should(qb0);
		}
		// 报警电话一致；
		if (!ValidationUtil.isEmpty(alertCalled.getEmergencyCall())) {
			flag = false;
			BoolQueryBuilder tempQb = QueryBuilders.boolQuery();
			BoolQueryBuilder tempQb1 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.termQuery("emergencyCall.keyword", alertCalled.getEmergencyCall()));
			tempQb.must(tempQb1);
			boolMust.should(tempQb);
		}
		// 使用单位名称一致；&&  ②警情类别一致；&&  ③报警时间：距离当前时间不超过两小时的
		if (!ValidationUtil.isEmpty(alertCalled.getUseUnit()) && !ValidationUtil.isEmpty(alertCalled.getAlarmTypeCode()) ) {
			flag = false;
			BoolQueryBuilder qb0 = QueryBuilders.boolQuery();
			BoolQueryBuilder temp1 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.termQuery("useUnit.keyword", alertCalled.getUseUnit()));
			qb0.must(temp1);

			BoolQueryBuilder temp2 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.termQuery("alarmTypeCode.keyword", alertCalled.getAlarmTypeCode()));
			qb0.must(temp2);

			//接警时间，距离当前时间不超过两个小时的
			long currentTime = System.currentTimeMillis() ;
			currentTime = currentTime - 120*60*1000;
			BoolQueryBuilder temp3 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.rangeQuery("callTimeLong").gte(currentTime));
			qb0.must(temp3);

			boolMust.should(qb0);
		}

		// 电梯识别码一致；&&  ③报警时间：距离当前时间不超过两小时的
		if (!ValidationUtil.isEmpty(alertCalled.getDeviceId())) {
			flag = false;
			BoolQueryBuilder qb0 = QueryBuilders.boolQuery();
			BoolQueryBuilder temp = QueryBuilders.boolQuery()
					.filter(QueryBuilders.termQuery("deviceId.keyword", alertCalled.getDeviceId()));
			qb0.must(temp);

			//接警时间，距离当前时间不超过两个小时的
			long currentTime = System.currentTimeMillis() ;
			currentTime = currentTime - 120*60*1000;
			BoolQueryBuilder temp2 = QueryBuilders.boolQuery()
					.filter(QueryBuilders.rangeQuery("callTimeLong").gte(currentTime));
			qb0.must(temp2);

			boolMust.should(qb0);
		}
		boolMust.minimumShouldMatch(1);//至少满足一个
		if(flag) { // 不搜素
			return result;
		}

        /**
         * 困人救援,故障报修,投诉咨询 条件构造
         */
		System.out.println(boolMust);
        // 创建查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                // 分页
                .withPageable(PageRequest.of(current, size))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMust);

        List<ESAlertCalledDto> list = new LinkedList<>();
        long totle = 0;
		try
		{
			SearchHits<ESAlertCalled> searchHits =elasticsearchTemplate.search(queryBuilder.build(), ESAlertCalled.class);
			
			for (SearchHit searchHit : searchHits.getSearchHits())
			{
				JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
				ESAlertCalledDto eSAlertCalled =JSONObject.toJavaObject(jsonObject, ESAlertCalledDto.class);
				list.add(eSAlertCalled);
			}
			totle =searchHits.getTotalHits();
		}
		catch (Exception e)
		{
			// TODO: handle exception
		}
        result.setRecords(list);
        result.setTotal(totle);

        return result;
    }

	/**
	 * 更新索引
	 */
	public ESAlertCalled updateEsAlertCalled(AlertCalledDto alertCalled) throws Exception {
		esAlertCalledRepository.deleteById(alertCalled.getSequenceNbr());
		ESAlertCalled esAlertCalled = new ESAlertCalled();
		esAlertCalled.setSequenceNbr(alertCalled.getSequenceNbr());
		esAlertCalled.setAlarmType(alertCalled.getAlarmType());
		esAlertCalled.setAlarmTypeCode(alertCalled.getAlarmTypeCode());
		esAlertCalled.setCallTime(alertCalled.getCallTime());
		esAlertCalled.setCallTimeLong(alertCalled.getCallTime()!=null?alertCalled.getCallTime().getTime():null);
		esAlertCalled.setContactPhone(alertCalled.getContactPhone());
		esAlertCalled.setAddress(alertCalled.getAddress());
		esAlertCalled.setAlertStage(alertCalled.getAlertStage());
		esAlertCalled.setAlertStatus(alertCalled.getAlertStatus());
		esAlertCalled.setEmergencyCall(alertCalled.getEmergencyCall());
		esAlertCalled.setDeviceId(alertCalled.getDeviceId());
		if (alertCalled.getAlertStatus())
		{
			esAlertCalled.setAlertStatusStr(AlertStatusEnum.CLOSED.getCode());
		}else
		{
			esAlertCalled.setAlertStatusStr(AlertStatusEnum.UNCLOSED.getCode());
		}
		esAlertCalledRepository.save(esAlertCalled);
		return esAlertCalled;
	}

}
