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

import cn.hutool.extra.pinyin.PinyinUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.module.jxiop.api.entity.StationBasic;
import com.yeejoin.amos.boot.module.jxiop.api.mapper.StationBasicMapper;
import com.yeejoin.amos.boot.module.jxiop.api.mapper.StationPlanMapper;
import com.yeejoin.amos.boot.module.jxiop.biz.ESDto.ESEquipments;
import com.yeejoin.amos.boot.module.jxiop.biz.constants.CommonConstans;
import com.yeejoin.amos.boot.module.jxiop.biz.dto.QueryDto;
import com.yeejoin.amos.boot.module.jxiop.biz.dto.SocialContributionDto;
import com.yeejoin.amos.boot.module.jxiop.biz.dto.StationCacheInfoDto;
import com.yeejoin.amos.boot.module.jxiop.biz.initdata.StationCacheDataInit;
import com.yeejoin.amos.boot.module.jxiop.biz.mapper2.SjglZsjZsbtzMapper;
import com.yeejoin.amos.boot.module.jxiop.biz.repository.ESEquipmentsRepository;
import com.yeejoin.amos.component.influxdb.InfluxdbUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
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.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

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

@Service
public class CommonServiceImpl {

    @Autowired
    InfluxdbUtil influxdbUtil;
    @Autowired
    SjglZsjZsbtzMapper sjglZsjZsbtzMapper;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;
    @Autowired
    ESEquipmentsRepository equipmentsRepository;
    @Autowired
    private StationCacheDataInit stationCacheDataInit;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StationBasicMapper stationBasicMapper;

    /**
     * 带参数 求平均值
     */
    public Double getavg(List<QueryDto> queryDto, String keyavg, Class clas) {
        Double value = null;
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        for (QueryDto dto : queryDto) {
            queryBuilder.must(QueryBuilders.termQuery(dto.getKey(), dto.getValue()));
        }
        AvgAggregationBuilder buyCountAvg = AggregationBuilders.avg("buyCountAvg").field(keyavg);
        Query query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(buyCountAvg)
                .withPageable(PageRequest.of(0, 1))
                .build();
        query.setTrackTotalHits(true);
        SearchHits search = elasticsearchTemplate.search(query, clas);
        if (search.hasAggregations()) {
            Aggregations aggregations = search.getAggregations();
            if (Objects.nonNull(aggregations)) {
                Avg avg = aggregations.get("buyCountAvg");
                value = avg.getValue();
            }
        }
        return value;
    }

    /*

     *分组平均值
     **/
    public List<? extends Terms.Bucket> getgroupavg(Map<String, List<String>> value, String keyavg, String groupKey, Class clas) {
        List<? extends Terms.Bucket> listdata = null;
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        for (String key : value.keySet()) {
            List<String> va = value.get(key);
            queryBuilder.must(QueryBuilders.termsQuery(key, va));
        }

        TermsAggregationBuilder tb1 = AggregationBuilders.terms("groupKey").field(groupKey);
        AvgAggregationBuilder buyCountAvg = AggregationBuilders.avg("buyCountAvg").field(keyavg);

        tb1.subAggregation(buyCountAvg);    // 通过typeId字段分组统计总数
        Query query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(tb1)
                .withPageable(PageRequest.of(0, 1))
                .build();
        query.setTrackTotalHits(true);
        SearchHits search = elasticsearchTemplate.search(query, ESEquipments.class);
        if (search.hasAggregations()) {
            Aggregations aggregations = search.getAggregations();
            if (Objects.nonNull(aggregations)) {
                List<Aggregation> list = aggregations.asList();
                listdata = list != null && !list.isEmpty() ? ((ParsedStringTerms) list.get(0)).getBuckets() : null;

            }
        }
        return listdata;
    }

    /*

     *分组求和
     **/
    public List<? extends Terms.Bucket> getgroupsum(Map<String, List<String>> value, String keyavg, String groupKey, Class clas) {
        List<? extends Terms.Bucket> listdata = null;
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        for (String key : value.keySet()) {
            List<String> va = value.get(key);
            queryBuilder.must(QueryBuilders.termsQuery(key, va));
        }

        TermsAggregationBuilder tb1 = AggregationBuilders.terms("groupKey").field(groupKey);
        SumAggregationBuilder buyCountSum = AggregationBuilders.sum("buyCountSum").field(keyavg);
        tb1.subAggregation(buyCountSum);    // 通过typeId字段分组统计总数
        Query query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(tb1)
                .withPageable(PageRequest.of(0, 1))
                .build();
        query.setTrackTotalHits(true);
        SearchHits search = elasticsearchTemplate.search(query, ESEquipments.class);
        if (search.hasAggregations()) {
            Aggregations aggregations = search.getAggregations();
            if (Objects.nonNull(aggregations)) {
                List<Aggregation> list = aggregations.asList();
                listdata = list != null && !list.isEmpty() ? ((ParsedStringTerms) list.get(0)).getBuckets() : null;

            }
        }
        return listdata;
    }

    /**
     * 带参数 求和
     */
    public Double getsum(List<QueryDto> queryDto, String keysum, Class clas) {
        Double value = null;
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        for (QueryDto dto : queryDto) {
            queryBuilder.must(QueryBuilders.termQuery(dto.getKey(), dto.getValue()));
        }
        SumAggregationBuilder buyCountSum = AggregationBuilders.sum("buyCountSum").field(keysum);
        Query query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .addAggregation(buyCountSum)
                .withPageable(PageRequest.of(0, 1))
                .build();
        query.setTrackTotalHits(true);
        SearchHits search = elasticsearchTemplate.search(query, clas);

        if (search.hasAggregations()) {
            Aggregations aggregations = search.getAggregations();
            if (Objects.nonNull(aggregations)) {
                Sum sum = aggregations.get("buyCountSum");
                value = sum.getValue();
            }
        }
        return value;
    }

    public Integer getCount(List<QueryDto> queryDto, String keysum, Class clas) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        for (QueryDto dto : queryDto) {
            queryBuilder.must(QueryBuilders.matchPhraseQuery(dto.getKey(), dto.getValue()));
        }
        Query query = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withPageable(PageRequest.of(0, 10000))
                .build();
        query.setTrackTotalHits(true);
        SearchHits search = elasticsearchTemplate.search(query, clas);
        return search.getSearchHits().size();
    }

    /**
     * @param gatewayId 网关id 用于拼接sql语句
     * @param indicator 指标名称  查询条件-根据指标名称获取风速
     * @return 指标值总和
     * @deprecated 获取指标值总和
     */
    public Double getTotalByIndicatior(String gatewayId, String indicator) {
        String sql = "SELECT * FROM indicators_" + gatewayId + " where equipmentIndexName='" + indicator + "'";
        Double totalvalue = 0.00;
        try {
            List<Map<String, Object>> mapList = influxdbUtil.query(sql);
            totalvalue = mapList.stream().filter(stringObjectMap -> !ObjectUtils.isEmpty(stringObjectMap.get("value"))).mapToDouble(l -> Double.parseDouble((String) l.get("value"))).sum();
        } catch (Exception e) {
            return totalvalue;
        }
        return Double.valueOf(String.format("%.2f", totalvalue));
    }

    public Double getTotalByIndicatiorAndParams(String gatewayId, String indicator, String querySql) {
        String sql = "SELECT * FROM indicators_" + gatewayId + " where equipmentIndexName='" + indicator + "'";
        Double totalvalue = 0.00;
        try {
            if (null != querySql) {
                sql = sql + " " + querySql;
            }
            List<Map<String, Object>> mapList = influxdbUtil.query(sql);
            totalvalue = mapList.stream().filter(stringObjectMap -> !ObjectUtils.isEmpty(stringObjectMap.get("value"))).mapToDouble(l -> Double.parseDouble((String) l.get("value"))).sum();
        } catch (Exception e) {
            return totalvalue;
        }
        return Double.valueOf(String.format("%.2f", totalvalue));
    }


    public Double getNumByIndicatior(String gatewayId, String indicator) {
        String sql = "SELECT * FROM indicators_" + gatewayId + " where equipmentIndexName=~/" + indicator + "$/";
        Double totalvalue = 0.00;
        try {
            List<Map<String, Object>> mapList = influxdbUtil.query(sql);
            totalvalue = mapList.stream().filter(stringObjectMap -> !ObjectUtils.isEmpty(stringObjectMap.get("value"))).mapToDouble(l -> Double.parseDouble((String) l.get("value"))).sum();
        } catch (Exception e) {
            return totalvalue;
        }
        return Double.valueOf(String.format("%.2f", totalvalue));
    }

    /**
     * @param gatewayId 网关id 用于拼接sql语句
     * @param indicator 指标名称  查询条件-根据指标名称获取风速
     * @return 指标值总和
     * @deprecated 获取指标值平均值
     */
    public Double getAvgvalueByIndicatior(String gatewayId, String indicator) {
        String sql = "SELECT * FROM indicators_" + gatewayId + " where equipmentIndexName='" + indicator + "'";
        Double avageValue = 0.00;
        try {
            List<Map<String, Object>> mapList = influxdbUtil.query(sql);
            avageValue = mapList.stream().filter(stringObjectMap -> !ObjectUtils.isEmpty(stringObjectMap.get("value"))).mapToDouble(l -> Double.parseDouble((String) l.get("value"))).average().getAsDouble();
        } catch (Exception e) {
            return avageValue;
        }
        return Double.valueOf(String.format("%.2f", avageValue));
    }

    public Double getTotalByIndicatior(List<Map<String, Object>> mapList, String indicator) {
        Double totalvalue = 0.0000;
        try {
            totalvalue = mapList.stream().filter(stringObjectMap -> stringObjectMap.get("equipmentIndexName").toString().contains(indicator) && !ObjectUtils.isEmpty(stringObjectMap.get("value"))).mapToDouble(l -> Double.parseDouble((String) l.get("value"))).sum();
        }catch (Exception e){
            return totalvalue;
        }
        return Double.valueOf(String.format("%.4f", totalvalue));
    }

    /**
     * @param indicator 指标名称  查询条件-根据指标名称获取风速
     * @return 指标值总和
     * @deprecated 获取指标值平均值
     */
    public Double getAvgvalueByIndicatior(List<Map<String, Object>> mapList, String indicator) {
        Double avageValue = 0.00;
        try {
            avageValue = mapList.stream().filter(stringObjectMap -> stringObjectMap.get("equipmentIndexName").toString().contains(indicator) && !ObjectUtils.isEmpty(stringObjectMap.get("value"))).mapToDouble(l -> Double.parseDouble((String) l.get("value"))).sum();
        }catch (Exception exception){
            return avageValue;
        }
        return Double.valueOf(String.format("%.2f", avageValue));
    }

    public Double getStationCapactityByStationWerks(String WERKS) {
        return sjglZsjZsbtzMapper.getStationCapactityByStationWerks(WERKS);
    }

    public Page<SocialContributionDto> getSocialContributionDtoList(Double totalSocialContribution) {
        Page<SocialContributionDto> socialContributionDtoPage = new Page<SocialContributionDto>();
        List<SocialContributionDto> socialContributionDtoList = new ArrayList<>();

        //获取所有网关id不为空的数据

        //二氧化碳贡献数
        SocialContributionDto co2 = new SocialContributionDto();
        //标准煤贡献度
        SocialContributionDto coal = new SocialContributionDto();
        //碳粉尘计算公式
        SocialContributionDto toner = new SocialContributionDto();
        //二氧化硫贡献度
        SocialContributionDto so2 = new SocialContributionDto();
        /** 社会贡献原始计算公式，后边的数据已经经过处理
         发电量完成率=（月/年）发电量/（月/年）发电量指标
         小时数完成率=（月/年）可利用小时/（月/年）可利用小时数指标
         可利用小时(h)=（日/月/年）发电量（万kW·h）/装机容量（万kW）
         二氧化碳减排量（万t）=发电量（万kW·h）*0.79
         节约标准煤（万t）=发电量（万kW·h）*0.29
         炭粉尘减排量（t）=发电量（万kW·h）*0.30
         二氧化硫减排量（t）=发电量（万kW·h）*1.51
         氮氧化物减排量（t）=发电量（万kW·h）*1.69
         */
        co2.setUnit("二氧化碳减排量（万t）");
        co2.setTitle(String.format("%.2f", totalSocialContribution * CommonConstans.carbonDioxide));
        socialContributionDtoList.add(co2);
        coal.setUnit("节约标准煤（万t）");
        coal.setTitle(String.format("%.2f", (totalSocialContribution * CommonConstans.standardCoal)));
        socialContributionDtoList.add(coal);
        toner.setUnit("碳粉尘减排量（万t）");
        toner.setTitle(String.format("%.2f", (totalSocialContribution * CommonConstans.toner * CommonConstans.tToWT)));
        socialContributionDtoList.add(toner);
        so2.setUnit("二氧化硫减排量（万t）");
        so2.setTitle(String.format("%.2f", (totalSocialContribution * CommonConstans.sulfurDioxide * CommonConstans.tToWT)));
        socialContributionDtoList.add(so2);
        socialContributionDtoPage.setRecords(socialContributionDtoList);
        socialContributionDtoPage.setTotal(100);
        socialContributionDtoPage.setCurrent(1);
        return socialContributionDtoPage;
    }

    public List<StationCacheInfoDto> getListStationCacheInfoDto() {
        List<StationCacheInfoDto> stationCacheInfoDtoList = redisTemplate.opsForList().range("station_info_cache", 0, -1);
        if (ObjectUtils.isEmpty(stationCacheInfoDtoList)) {
            try {
                stationCacheDataInit.run();
                stationCacheInfoDtoList = redisTemplate.opsForList().range("station_info_cache", 0, -1);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return stationCacheInfoDtoList;
    }

    public StationCacheInfoDto getStationCacheInfoDtoByStationId(String stationId) {
        return getListStationCacheInfoDto().stream().filter(stationCacheInfoDto -> stationCacheInfoDto.getStationId().equals(stationId)).collect(Collectors.toList()).get(0);
    }

    public String getFanDevicePrefix(String stationid) {
        StationBasic stationBasic = stationBasicMapper.selectById(stationid);
        return PinyinUtil.getFirstLetter(stationBasic.getStationName().split("风")[0], "").toUpperCase(Locale.ROOT);
    }
}
