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

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.annotation.PostConstruct;

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.context.annotation.DependsOn;
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 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.jcs.api.dto.ESAlertCalledDto;
import com.yeejoin.amos.boot.module.jcs.api.dto.ESAlertCalledRequestDto;
import com.yeejoin.amos.boot.module.jcs.api.entity.AlertCalled;
import com.yeejoin.amos.boot.module.jcs.api.entity.ESAlertCalled;
import com.yeejoin.amos.boot.module.jcs.api.enums.AlertStatusEnum;
import com.yeejoin.amos.boot.module.jcs.biz.dao.ESAlertCalledRepository;
/**
 *
 * <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);
        wrapper.isNull("father_alert");

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

    /**
     *
     * <pre>
     * 批量保存
     * </pre>
     *
     * @param list 警情信息列表
     */
    public void saveAll(List<AlertCalled> alertCalleds) throws Exception{

    	if (!ValidationUtil.isEmpty(alertCalleds))
		{
			for (AlertCalled alertCalled : alertCalleds)
			{
				this.saveAlertCalledToES(alertCalled);
			}
		}
    }

    /**
     *
     * <pre>
     * 根据警情记录批量保存
     * </pre>
     *
     * @param alertCalleds 警情信息列表
     */
    public ESAlertCalled saveAlertCalledToES(AlertCalled alertCalled) throws Exception
    {
    	ESAlertCalled esAlertCalled = new ESAlertCalled();
    	esAlertCalled.setSequenceNbr(alertCalled.getSequenceNbr());
    	esAlertCalled.setAlertType(alertCalled.getAlertType());
    	esAlertCalled.setAlertTypeCode(alertCalled.getAlertTypeCode());
    	esAlertCalled.setCallTime(alertCalled.getCallTime());
    	esAlertCalled.setCallTimeLong(alertCalled.getCallTime()!=null?alertCalled.getCallTime().getTime():null);
    	esAlertCalled.setContactUser(alertCalled.getContactUser());
    	esAlertCalled.setContactPhone(alertCalled.getContactPhone());
    	esAlertCalled.setAddress(alertCalled.getAddress());
    	esAlertCalled.setAlertStage(alertCalled.getAlertStage());
    	esAlertCalled.setAlertStatus(alertCalled.getAlertStatus());
    	if (alertCalled.getAlertStatus())
    	{
    		esAlertCalled.setAlertStatusStr(AlertStatusEnum.CLOSED.getCode());
    	}else
    	{
    		esAlertCalled.setAlertStatusStr(AlertStatusEnum.UNCLOSED.getCode());
    	}
    	esAlertCalled.setResponseLevelCode(alertCalled.getResponseLevelCode());
    	esAlertCalled.setUnitInvolved(alertCalled.getUnitInvolved());
    	esAlertCalled.setCoordinateX(alertCalled.getCoordinateX());
    	esAlertCalled.setCoordinateY(alertCalled.getCoordinateY());

    	esAlertCalledRepository.save(esAlertCalled);

    	return esAlertCalled;
    }

    /**
     *
     * <pre>
     *  从ES库批量删除
     * </pre>
     *
     * @param ids
     * @return
     * @throws Exception
     */
    public Boolean deleteById(List<Long> ids) throws Exception{
        if (!ValidationUtil.isEmpty(ids)) {
        	for (Long sequenceNbr : ids) {
        		if (esAlertCalledRepository.existsById(sequenceNbr)) {
        			esAlertCalledRepository.deleteById(sequenceNbr);
        		}
        	}
        }

        return true;
    }

    /**
     * 根据id查询ES存储对象
     *
     * @param sequenceNbr id
     * @return ES实例
     */
    public ESAlertCalled queryById(Long sequenceNbr) {
        return esAlertCalledRepository.findById(sequenceNbr).orElse(null);
    }

    /**
     * 根据关键字查询文档，关键字不为空时按相关性从大到小排序
     *
     * @param queryStr 关键字
     * @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 = alertCalledVo.getAlertCalled();
    	if (ValidationUtil.isEmpty(alertCalled))
		{
			return result;
		}
        /**
         * 通用匹配规则，条件构建
         */
    	BoolQueryBuilder boolMustAll = QueryBuilders.boolQuery();
    	//警情状态
    	BoolQueryBuilder qb0 = QueryBuilders.boolQuery();
    	for (String status : alertStatus)
		{
    		AlertStatusEnum alertStatusEnum = AlertStatusEnum.getEnum(status);
    		if (!ValidationUtil.isEmpty(alertStatusEnum))
			{
    			qb0.should(QueryBuilders.termQuery("alertStatusStr.keyword", alertStatusEnum.getCode()));
			}
		}
    	boolMustAll.must(qb0);
    	
    	BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        //接警时间，距离当前时间不超过半小时的
        long currentTime = System.currentTimeMillis() ;
        currentTime = currentTime - 30*60*1000;
        BoolQueryBuilder qb1 = QueryBuilders.boolQuery()
        		.must(QueryBuilders.rangeQuery("callTimeLong").gte(currentTime));
        boolMust.should(qb1);
        //报警人及报警电话一致
        if (!ValidationUtil.isEmpty(alertCalled.getContactUser()) && !ValidationUtil.isEmpty(alertCalled.getContactPhone()))
		{
        	BoolQueryBuilder qb2 = QueryBuilders.boolQuery()
        			.must(QueryBuilders.termQuery("contactUser.keyword", alertCalled.getContactUser()))
        			.must(QueryBuilders.termQuery("contactPhone.keyword", alertCalled.getContactPhone()));
        	boolMust.should(qb2);
		}
        //事发地点一致，或相距不超过200米的
        if (!ValidationUtil.isEmpty(alertCalled.getAddress()))
		{
        	BoolQueryBuilder qb3 = QueryBuilders.boolQuery()
        			.should(QueryBuilders.matchQuery("address", alertCalled.getAddress()));
        	boolMust.should(qb3);
		}
        //警情类型一致
        BoolQueryBuilder qb4 = QueryBuilders.boolQuery()
        		.must(QueryBuilders.termQuery("alertTypeCode.keyword", alertCalled.getAlertTypeCode()));
        boolMust.should(qb4);
        //事发单位名称一致
        if (!ValidationUtil.isEmpty(alertCalled.getUnitInvolved()))
		{
        	BoolQueryBuilder qb5 = QueryBuilders.boolQuery()
        			.must(QueryBuilders.matchQuery("unitInvolved", alertCalled.getUnitInvolved()));
        	boolMust.should(qb5);
		}

        /**
         * 一般火灾，条件构造
         */


        boolMust.minimumShouldMatch(1);//至少满足一个
        boolMustAll.must(boolMust);
        // 创建查询构造器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
                // 分页
                .withPageable(PageRequest.of(current, size))
                // 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
                //过滤条件
                .withQuery(boolMustAll);

        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;
    }

}
