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

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.module.cylinder.biz.dao.ESCylinderRepository;
import com.yeejoin.amos.boot.module.cylinder.flc.biz.service.impl.CylinderUnitServiceImpl;
import com.yeejoin.amos.boot.module.cylinder.flc.biz.service.impl.EndUserServiceImpl;
import com.yeejoin.amos.boot.module.cylinder.api.dto.EsSpecialEquipmentDto;
import com.yeejoin.amos.boot.module.cylinder.api.dto.SpecialEquipmentDto;
import com.yeejoin.amos.boot.module.cylinder.api.entity.EsCylinder;
import com.yeejoin.amos.boot.module.cylinder.api.enums.SpecialEquipmentCategoryEnum;
import com.yeejoin.amos.boot.module.cylinder.flc.api.entity.CylinderInfo;
import com.yeejoin.amos.boot.module.cylinder.flc.api.entity.CylinderUnit;
import com.yeejoin.amos.boot.module.cylinder.flc.api.entity.EndUser;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
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.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

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

/**
 * <pre>
 * 压力容器信息ES检索服务
 * </pre>
 *
 * @author tb
 * @version 2022年4月20日
 */
@Service
public class ESCylinderServiceImpl {

	@Autowired
	private ElasticsearchRestTemplate elasticsearchTemplate;

	@Autowired
	private ESCylinderRepository esCylinderRepository;

	@Autowired
	private EndUserServiceImpl endUserService;

	@Autowired
	private CylinderUnitServiceImpl cylinderUnitService;

	/**
	 * <pre>
	 * 保存气瓶信息
	 * </pre>
	 *
	 * @param cylinderInfoList 保存气瓶信息
	 */
	public boolean saveEsCylinderToES(List<CylinderInfo> cylinderInfoList) {
		List<EsCylinder> esCylinderList = Lists.newArrayList();
		if (!ValidationUtil.isEmpty(cylinderInfoList)) {
			cylinderInfoList.forEach(cylinderInfo -> {
				EsCylinder esCylinder = new EsCylinder();
				if (StringUtils.isNotEmpty(cylinderInfo.getLongitude())) {
					esCylinder.setLongitude(Double.parseDouble(cylinderInfo.getLongitude()));
				}
				if (StringUtils.isNotEmpty(cylinderInfo.getLatitude())) {
					esCylinder.setLatitude(Double.parseDouble(cylinderInfo.getLatitude()));
				}
				esCylinder.setSequenceNbr(cylinderInfo.getSequenceNbr());
				EndUser endUser = endUserService.getOne(new LambdaQueryWrapper<EndUser>().eq(EndUser::getCustomCode,
						cylinderInfo.getEndCustomCode()));
				if (!ValidationUtil.isEmpty(endUser)) {
                    esCylinder.setAddress(endUser.getAddress());
				}
				CylinderUnit cylinderUnit =
						cylinderUnitService.getOne(new LambdaQueryWrapper<CylinderUnit>().eq(CylinderUnit::getAppId,
								cylinderInfo.getAppId()));
				if (!ValidationUtil.isEmpty(cylinderUnit)) {
					esCylinder.setRegionCode(cylinderUnit.getRegionCode());
				}
				esCylinder.setFactoryNum(cylinderInfo.getFactoryNum());
				esCylinder.setUnitName(cylinderInfo.getUnitName());
				if (StringUtils.isNotBlank(cylinderInfo.getLatitude()) && StringUtils.isNotBlank(cylinderInfo.getLongitude())) {
					double lat = Double.parseDouble(cylinderInfo.getLatitude());
					double lon = Double.parseDouble(cylinderInfo.getLongitude());
					esCylinder.setLocation(new GeoPoint(lat, lon));
				}
				esCylinderList.add(esCylinder);
			});
		}
		esCylinderRepository.saveAll(esCylinderList);
		return true;
	}

	public Page<SpecialEquipmentDto> queryPageByDto(EsSpecialEquipmentDto esSpecialEquipmentDto, int current, int size) {
		Page<SpecialEquipmentDto> result = new Page<>(current, size);
		Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
		Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
		Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
		Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
		String regionCode = esSpecialEquipmentDto.getRegionCode();
		String keyword = esSpecialEquipmentDto.getKeyword();
		/**
		 * 通用匹配规则，条件构建
		 */
		BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
		// 经度比start 大比end 小 纬度比start 小 比end 大
		if (!ValidationUtil.isEmpty(startLongitude) && !ValidationUtil.isEmpty(startLatitude) && !ValidationUtil.isEmpty(endLongitude) && !ValidationUtil.isEmpty(endLatitude)) {
			BoolQueryBuilder longLatMust = QueryBuilders.boolQuery();
			BoolQueryBuilder qb1 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("longitude").gte(startLongitude).lte(endLongitude));
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("latitude").gte(endLatitude).lte(startLatitude));
			longLatMust.must(qb1);
			longLatMust.must(qb2);
			boolMust.must(longLatMust);
		}

		if (!ValidationUtil.isEmpty(regionCode)) {
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().
					filter(QueryBuilders.matchPhraseQuery("regionCode", regionCode));
			boolMust.must(qb2);
		}

		if (!ValidationUtil.isEmpty(keyword)) {
			BoolQueryBuilder qb0 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("factoryNum", keyword));
			boolMust.should(qb0);
			BoolQueryBuilder qb1 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("address", keyword));
			boolMust.should(qb1);
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("unitName", keyword));
			boolMust.should(qb2);
			boolMust.minimumShouldMatch(1);
		}

		// 创建查询构造器
		NativeSearchQuery query = new NativeSearchQueryBuilder()
				// 分页
				.withPageable(PageRequest.of(current - 1, size))
				// 排序
//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
				//过滤条件
				.withQuery(boolMust).build();
		query.setTrackTotalHits(true);
		query.setMaxResults(size);
		List<SpecialEquipmentDto> list = new LinkedList<>();
		long total = 0;
		try {
			SearchHits<EsCylinder> searchHits = elasticsearchTemplate.search(query, EsCylinder.class);

			for (SearchHit searchHit : searchHits.getSearchHits()) {
				JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
				SpecialEquipmentDto esCylinderDto = JSONObject.toJavaObject(jsonObject, SpecialEquipmentDto.class);
				esCylinderDto.setCategoryCode(SpecialEquipmentCategoryEnum.PRESSURE_VESSEL.getCode());
				esCylinderDto.setUnitName(jsonObject.getString("unitName"));
				esCylinderDto.setRegisterCode(jsonObject.getString("factoryNum"));
				list.add(esCylinderDto);
			}
			total = searchHits.getTotalHits();
		} catch (Exception e) {
			// TODO: handle exception
		}
		result.setRecords(list);
		result.setTotal(total);
		return result;
	}

	public Long queryNumberByDto(EsSpecialEquipmentDto esSpecialEquipmentDto) {
		Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
		Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
		Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
		Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
		String regionCode = esSpecialEquipmentDto.getRegionCode();
		String keyword = esSpecialEquipmentDto.getKeyword();
		/**
		 * 通用匹配规则，条件构建
		 */
		BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
		// 经度比start 大比end 小 纬度比start 小 比end 大
		if (!ValidationUtil.isEmpty(startLongitude) && !ValidationUtil.isEmpty(startLatitude) && !ValidationUtil.isEmpty(endLongitude) && !ValidationUtil.isEmpty(endLatitude)) {
			BoolQueryBuilder longLatMust = QueryBuilders.boolQuery();
			BoolQueryBuilder qb1 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("longitude").gte(startLongitude).lte(endLongitude));
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("latitude").gte(endLatitude).lte(startLatitude));
			longLatMust.must(qb1);
			longLatMust.must(qb2);
			boolMust.must(longLatMust);
		}

		if (!ValidationUtil.isEmpty(regionCode)) {
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().
					filter(QueryBuilders.matchPhraseQuery("regionCode", regionCode));
			boolMust.must(qb2);
		}

		if (!ValidationUtil.isEmpty(keyword)) {
			BoolQueryBuilder qb0 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("factoryNum", keyword));
			boolMust.should(qb0);
			BoolQueryBuilder qb1 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("address", keyword));
			boolMust.should(qb1);
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("unitName", keyword));
			boolMust.should(qb2);
			boolMust.minimumShouldMatch(1);
		}

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


		long total = 0;
		try {
			SearchHits<EsCylinder> searchHits = elasticsearchTemplate.search(queryBuilder.build(), EsCylinder.class);
			total = searchHits.getTotalHits();
		} catch (Exception e) {
			// TODO: handle exception
		}
		return total;
	}

	/**
	 * 根据特种设备搜索类查找气瓶相关信息
	 *
	 * @param esSpecialEquipmentDto
	 * @return
	 */
	public List<SpecialEquipmentDto> queryByDto(EsSpecialEquipmentDto esSpecialEquipmentDto) {

		Double startLongitude = esSpecialEquipmentDto.getStartLongitude();
		Double startLatitude = esSpecialEquipmentDto.getStartLatitude();
		Double endLongitude = esSpecialEquipmentDto.getEndLongitude();
		Double endLatitude = esSpecialEquipmentDto.getEndLatitude();
		String regionCode = esSpecialEquipmentDto.getRegionCode();
		String keyword = esSpecialEquipmentDto.getKeyword();
		// 如果传入经纬度则根据经纬度过滤 如果传入regionCode 根据regionCode过滤 如果是 单独查电梯 则返回最多3000条 否则为 400条
		/**
		 * 通用匹配规则，条件构建
		 */
		BoolQueryBuilder boolMust = QueryBuilders.boolQuery();


		// 经度比start 大比end 小 纬度比start 小 比end 大
		if (!ValidationUtil.isEmpty(startLongitude) && !ValidationUtil.isEmpty(startLatitude) && !ValidationUtil.isEmpty(endLongitude) && !ValidationUtil.isEmpty(endLatitude)) {
			BoolQueryBuilder longLatMust = QueryBuilders.boolQuery();
			BoolQueryBuilder qb1 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("longitude").gte(startLongitude).lte(endLongitude));
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("latitude").gte(endLatitude).lte(startLatitude));
			longLatMust.must(qb1);
			longLatMust.must(qb2);
			boolMust.must(longLatMust);
		}

		if (!ValidationUtil.isEmpty(regionCode)) {
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().
					filter(QueryBuilders.matchPhraseQuery("regionCode", regionCode));
			boolMust.must(qb2);
		}

		if (!ValidationUtil.isEmpty(keyword)) {
			BoolQueryBuilder qb0 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("factoryNum", keyword));
			boolMust.should(qb0);
			BoolQueryBuilder qb1 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("address", keyword));
			boolMust.should(qb1);
			BoolQueryBuilder qb2 = QueryBuilders.boolQuery().
					must(QueryBuilders.matchQuery("unitName", keyword));
			boolMust.should(qb2);
			boolMust.minimumShouldMatch(1);
		}

		// 创建查询构造器
		NativeSearchQuery query = new NativeSearchQueryBuilder()
				// 分页
				//               .withPageable(PageRequest.of(0, size))
				// 排序
				//                .withSort(SortBuilders.fieldSort("callTimeLong").order(SortOrder.DESC))
				//过滤条件
				.withQuery(boolMust).build();
		query.setTrackTotalHits(true);
		query.setMaxResults(10000);

		List<SpecialEquipmentDto> list = new LinkedList<>();
		SearchHits<EsCylinder> searchHits = elasticsearchTemplate.search(query, EsCylinder.class);
		for (SearchHit searchHit : searchHits.getSearchHits()) {
			JSONObject jsonObject = (JSONObject) JSONObject.toJSON(searchHit.getContent());
			SpecialEquipmentDto esCylinderDto = JSONObject.toJavaObject(jsonObject, SpecialEquipmentDto.class);
			esCylinderDto.setCategoryCode(SpecialEquipmentCategoryEnum.PRESSURE_VESSEL.getCode());
			esCylinderDto.setUnitName(jsonObject.getString("unitName"));
			esCylinderDto.setRegisterCode(jsonObject.getString("factoryNum"));
			list.add(esCylinderDto);
		}
		return list;
	}
}
