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

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeejoin.amos.boot.module.cylinder.api.dto.KeyValueDto;
import com.yeejoin.amos.boot.module.cylinder.api.entity.ESCylinderFillingRecordDto;
import com.yeejoin.amos.boot.module.cylinder.biz.dao.ESCylinderFillingRecordRepository;
import com.yeejoin.amos.boot.module.cylinder.flc.api.dto.CityCylinderInfoDto;
import com.yeejoin.amos.boot.module.cylinder.flc.api.dto.CylinderAreaDataDto;
import com.yeejoin.amos.boot.module.cylinder.flc.api.entity.CylinderAreaData;
import com.yeejoin.amos.boot.module.cylinder.flc.api.mapper.CylinderAreaDataMapper;
import com.yeejoin.amos.boot.module.cylinder.flc.api.service.ICylinderAreaDataService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 气瓶区域统计表服务实现类
 *
 * @author system_generator
 * @date 2022-03-08
 */
@Service
public class CylinderAreaDataServiceImpl extends BaseService<CylinderAreaDataDto, CylinderAreaData, CylinderAreaDataMapper> implements ICylinderAreaDataService {

    public final static String LICENSE_IS_OK = "正常";

    public final static String NO_DATA_STR = "--";

    @Autowired
    RestHighLevelClient restHighLevelClient;

    @Autowired
    ESCylinderFillingRecordRepository esCylinderFillingRecordRepository;

    /**
     * 分页查询
     */
    public Page<CylinderAreaDataDto> queryForCylinderAreaDataPage(Page<CylinderAreaDataDto> page) {
        return this.queryForPage(page, null, false);
    }

    /**
     * 列表查询 示例
     */
    public List<CylinderAreaDataDto> queryForCylinderAreaDataList() {
        return this.queryForList("", false);
    }

    public List<CityCylinderInfoDto> getCityCylinderData(String level) {
        return this.queryForList("", false, level).stream()
                .map(v -> CityCylinderInfoDto.builder()
                        .regionName(v.getAreaName())
                        .regionCode(v.getRegionCode())
                        .longitude(v.getLongitude())
                        .latitude(v.getLatitude())
                        .isAlarm(v.getOutOfDateNum() != 0)
                        .cylindersCount(v.getCylinderNum())
                        .stationCount(v.getUnitNum())
                        .build())
                .collect(Collectors.toList());
    }

    public Page<Map<String, Object>> getEarlyWarningStatistics(String regionCode, String appId) {
        Page<Map<String, Object>> page = new Page<>();
        // 是否有充装企业在指定区域下
        Boolean isHavingUnitInRegion = true;
        List<Map<String, Object>> list = Lists.newArrayList();
        Map<String, Object> result1 = Maps.newHashMap();
        Map<String, Object> result2 = Maps.newHashMap();
        // 1.许可有效率
        if (!ValidationUtil.isEmpty(appId)) {
            result1.put("name", "许可有效期");
            result1.put("value", this.getBaseMapper().queryLicenseEfficiencyOneCompany(appId).getStrValue());
        } else if (!ValidationUtil.isEmpty(regionCode)) {
            result1.put("name", "许可有效率(%)");
            result1.put("value", this.getLicenseEfficiencyByRegion(regionCode));
            isHavingUnitInRegion = this.setNoUnitDataStaticInfo(list, result1.get("value").toString());
        }
        if (!ValidationUtil.isEmpty(regionCode) && !isHavingUnitInRegion) {
            return page.setRecords(list);
        }
        // 2.使用登记办理率
        if (!ValidationUtil.isEmpty(appId)) {
            result2.put("name", "使用登记");
            result2.put("value", "已办理");
        } else {
            result2.put("name", "使用登记办理率(%)");
            result2.put("value", "100");
        }
        // 3.检验超期率
        Map<String, Object> result3 = Maps.newHashMap();
        result3.put("name", "检验超期率(%)");
        result3.put("value", this.getBaseMapper().getInspectionExpiredRate(regionCode, appId).get("expiredRate").toString());
        // 4.检验合格率
        Map<String, Object> result4 = Maps.newHashMap();
        result4.put("name", "检验合格率(%)");
        result4.put("value", this.getBaseMapper().getInspectionResultRate(regionCode, appId).get("resultRate").toString());
        // 5.充装检查率
        Map<String, Object> result5 = Maps.newHashMap();
        long totalAll = searchEsCount(false, false, regionCode, appId);
        long totalCheck = searchEsCount(true, false, regionCode, appId);
        long totalResult = searchEsCount(false, true, regionCode, appId);
        result5.put("name", "充装检查率(%)");
        if (totalAll != 0) {
            result5.put("value", new DecimalFormat("#.00").format(((double) totalCheck / totalAll) * 100));
        } else {
            result5.put("value", 0);
        }
        // 6.充装检查合格率
        Map<String, Object> result6 = Maps.newHashMap();
        result6.put("name", "充装检查合格率(%)");
        if (totalAll != 0) {
            result6.put("value", new DecimalFormat("#.00").format(((double) totalResult / totalAll) * 100));
        } else {
            result6.put("value", 0);
        }

        // list中按以下固定顺序返回给前端
        list.add(result1);
        list.add(result3);
        list.add(result5);
        list.add(result2);
        list.add(result4);
        list.add(result6);
        page.setRecords(list);
        return page;
    }

    private Boolean setNoUnitDataStaticInfo(List<Map<String, Object>> list, String value) {
        if (NO_DATA_STR.equals(value)) {
            Map<String, Object> result2 = Maps.newHashMap();
            result2.put("name", "使用登记办理率(%)");
            result2.put("value", NO_DATA_STR);
            Map<String, Object> result3 = Maps.newHashMap();
            result3.put("name", "检验超期率(%)");
            result3.put("value", NO_DATA_STR);
            Map<String, Object> result4 = Maps.newHashMap();
            result4.put("name", "检验合格率(%)");
            result4.put("value", NO_DATA_STR);
            Map<String, Object> result5 = Maps.newHashMap();
            result5.put("name", "充装检查率(%)");
            result5.put("value", NO_DATA_STR);
            Map<String, Object> result6 = Maps.newHashMap();
            result6.put("name", "充装检查合格率(%)");
            result6.put("value", NO_DATA_STR);
            list.add(result2);
            list.add(result3);
            list.add(result5);
            list.add(result4);
            list.add(result6);
            return false;
        }
        return true;
    }

    private String getLicenseEfficiencyByRegion(String regionCode) {
        List<KeyValueDto> keyValueDtos = this.getBaseMapper().queryLicenseEfficiencyOfRegion(regionCode);
        int totalUnitNumber = keyValueDtos.stream().mapToInt(KeyValueDto::getIValue).sum();
        int okUnitNumberNumber = keyValueDtos.stream().filter(k -> k.getStrKey().equals(LICENSE_IS_OK)).mapToInt(KeyValueDto::getIValue).sum();
        if (totalUnitNumber == 0) {
            return NO_DATA_STR;
        }
        BigDecimal bigTotalUnitNumber = new BigDecimal(String.valueOf(totalUnitNumber));
        BigDecimal bigOkUnitNumberNumber = new BigDecimal(String.valueOf(okUnitNumberNumber));
        BigDecimal result = bigOkUnitNumberNumber.divide(bigTotalUnitNumber, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")).setScale(2);
        return result.toPlainString();
    }

    private long searchEsCount(Boolean checkOk, Boolean resultOk, String regionCode, String appId) {
        CountRequest countRequest = new CountRequest("cylinder_filling");
//        countRequest.indices("cylinder_filling");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        if (checkOk) {
            //匹配充装前检查和充装后检查都有数据
            BoolQueryBuilder meBuilder = QueryBuilders.boolQuery();
            meBuilder.must(QueryBuilders.existsQuery("inspectionDateMs"));
            meBuilder.must(QueryBuilders.existsQuery("inspectionDateAfterMS"));
            boolMust.must(meBuilder);
        }
        if (resultOk) {
            //匹配充装前检查和充装后检查都有数据
            BoolQueryBuilder meBuilder = QueryBuilders.boolQuery();
            meBuilder.must(QueryBuilders.termQuery("fillingResult.keyword", "合格"));
            meBuilder.must(QueryBuilders.termQuery("checkResult.keyword", "合格"));
            boolMust.must(meBuilder);
        }

        //匹配行政区划
        if (!ObjectUtils.isEmpty(regionCode)) {
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            query.must(QueryBuilders.wildcardQuery("regionCode", "*" + regionCode + "*"));
            boolMust.must(query);
        }
        //匹配appId
        if (!ObjectUtils.isEmpty(appId)) {
            BoolQueryBuilder query = QueryBuilders.boolQuery();
            query.must(QueryBuilders.matchQuery("appId", appId));
            boolMust.must(query);
        }

        countRequest.query(boolMust);
        try {
            CountResponse countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            return countResponse.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public String testSaveCylinderFillingRecord2ES() {
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("cylinder_filling");
        List<ESCylinderFillingRecordDto> dtoList = Lists.newArrayList();
        ESCylinderFillingRecordDto esCylinderFillingRecordDto = new ESCylinderFillingRecordDto();
        esCylinderFillingRecordDto.setAppId("1");
        esCylinderFillingRecordDto.setCreditCode("1");
        esCylinderFillingRecordDto.setCheckResult("合格");
        esCylinderFillingRecordDto.setFillingResult("合格");
        esCylinderFillingRecordDto.setUnitName("1test1");
        dtoList.add(esCylinderFillingRecordDto);
        ESCylinderFillingRecordDto esCylinderFillingRecordDto1 = new ESCylinderFillingRecordDto();
        esCylinderFillingRecordDto1.setAppId("1");
        esCylinderFillingRecordDto1.setCreditCode("1");
        esCylinderFillingRecordDto1.setCheckResult("合格");
        esCylinderFillingRecordDto1.setFillingResult("合格");
        esCylinderFillingRecordDto1.setUnitName("1test1");
        dtoList.add(esCylinderFillingRecordDto1);
        esCylinderFillingRecordRepository.saveAll(dtoList);
        return "success";
    }
}