package com.njcn.prepare.harmonic.service.mysql.Impl.area;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njcn.device.pms.pojo.po.Monitor;
import com.njcn.device.pq.constant.Param;
import com.njcn.device.pq.pojo.po.PmsAbnormalRules;
import com.njcn.harmonic.pojo.po.PmsMonitorPO;
import com.njcn.harmonic.pojo.po.RMpIntegrityDPO;
import com.njcn.harmonic.pojo.po.RStatAbnormalDPO;
import com.njcn.prepare.harmonic.constant.AlgorithmParam;
import com.njcn.prepare.harmonic.mapper.mysql.area.RStatAbnormalDPOMapper;
import com.njcn.prepare.harmonic.mapper.mysql.line.PmsAbnormalRulesMapper;
import com.njcn.prepare.harmonic.pojo.dto.DataVFiveItemDTO;
import com.njcn.prepare.harmonic.pojo.oracle.PqLinedetailPO;
import com.njcn.prepare.harmonic.pojo.param.PrimaryGridParam;
import com.njcn.prepare.harmonic.service.influxdb.DataVInfluxdbService;
import com.njcn.prepare.harmonic.service.mysql.area.EffectiveMinuteCountService;
import com.njcn.prepare.harmonic.service.mysql.area.PmsMonitorPOService;
import com.njcn.prepare.harmonic.service.mysql.area.RMpIntegrityDPOService;
import com.njcn.prepare.harmonic.service.oracle.DataVOraclePOService;
import com.njcn.prepare.harmonic.service.oracle.PqLinedetailPOService;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Description:
 * 接口文档访问地址：http://serverIP:port/swagger-ui.html
 * Date: 2023/2/23  16:04【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
@Service
@RequiredArgsConstructor
public class EffectiveMinuteCountServiceImpl implements EffectiveMinuteCountService {

    private final
    PmsMonitorPOService pmsMonitorPOService;
    private final
    RStatAbnormalDPOMapper rStatAbnormalDPOMapper;
    private final
    PmsAbnormalRulesMapper pmsAbnormalRulesMapper;
    private final
    PqLinedetailPOService pqLinedetailPOService;
    private final
    DataVOraclePOService dataVOraclePOService;
    private final
    RMpIntegrityDPOService rMpIntegrityDPOService;
    private final
    DicDataFeignClient dicDataFeignClient;
    private final
    DataVInfluxdbService dataVInfluxdbService;


    /**
     * @param primaryGridParam
     * @Description: 主网有效监测时长计算
     * @Param: [primaryGridParam]
     * @return: void
     * @Author: clam
     * @Date: 2023/2/23
     */
    @Override
    @Async("asyncExecutor")
    public void effectiveMinuteCount(PrimaryGridParam primaryGridParam) {
        if (Objects.equals (primaryGridParam.getDataSource ( ), AlgorithmParam.ORACLE_DATA)) {
            this.hanlderOracleData (primaryGridParam);
        } else if (Objects.equals (primaryGridParam.getDataSource ( ), AlgorithmParam.INFLUX_DATA)) {
            this.hanlderInfludxbData (primaryGridParam);
        }
    }

    private void hanlderInfludxbData(PrimaryGridParam primaryGridParam) {
        Integer type = primaryGridParam.getType ( );
        switch (type) {
//            case 1:
//                this.hanlderInfludxdbYear (primaryGridParam);
//                break;
//            case 2:
//                this.hanlderInfludxdbQtr (primaryGridParam);
//                break;
//            case 3:
//                this.hanlderInfludxdbMonth (primaryGridParam);
//                break;
            case 5:
                this.hanlderInfludxdbDay (primaryGridParam);
                break;
            default:
                break;
        }
    }
    @SneakyThrows
    private void hanlderInfludxdbDay(PrimaryGridParam primaryGridParam) {
        List<String> orgIdList = primaryGridParam.getOrgIdList ( );
        String dataDate = primaryGridParam.getDataDate ( );
        List<RMpIntegrityDPO> rMpIntegrityDPOS = new ArrayList<> ( );

        //1、取出规则
        List<PmsAbnormalRules> pmsAbnormalRules = pmsAbnormalRulesMapper.selectList (null);
        //2、取出电压字典
        List<DictData> dictDataList = dicDataFeignClient.getDicDataByTypeName (DicDataTypeEnum.DEV_VOLTAGE.getName ( )).getData ( );


        final Date tempDate = new SimpleDateFormat ("yyyy-MM-dd").parse (dataDate);
        orgIdList.forEach (orgid -> {
            /*主网在运监测点*/
            List<Monitor> pmsMonitorPOS = pmsMonitorPOService.qurymeasurementRunPoints (orgid);
            List<String> mysqlIndexList = pmsMonitorPOS.stream ( ).map (Monitor::getId).collect (Collectors.toList ( ));
            if (CollectionUtil.isEmpty (mysqlIndexList)) {
                return;
            }
            /*过滤掉异常监测点*/
            QueryWrapper<RStatAbnormalDPO> rStatAbnormalDPOLambdaQueryWrapper = new QueryWrapper ( );
            rStatAbnormalDPOLambdaQueryWrapper.select ("measurementPointId").
                    in ("measurement_point_id", mysqlIndexList).
                    eq ("value_alarm", 1).
                    eq ("DATE_FORMAT( data_date ,'%Y-%m-%d')", dataDate);
            List<RStatAbnormalDPO> rStatAbnormalDPOS = rStatAbnormalDPOMapper.selectList (rStatAbnormalDPOLambdaQueryWrapper);
            List<String> collect = rStatAbnormalDPOS.stream ( ).map (RStatAbnormalDPO::getMeasurementPointId).collect (Collectors.toList ( ));
            List<Monitor> collect1 = pmsMonitorPOS.stream ( ).filter (temp -> collect.contains (temp.getId ( ))).collect (Collectors.toList ( ));
//            /*测试造的数据*/
//            List<PmsMonitorPO> collect1 = new ArrayList<> ();
//            PmsMonitorPO pmsMonitorPO = new PmsMonitorPO();
//            pmsMonitorPO.setVoltageLevel ("e3da890104e3c4ae1f005021411a1fd7");
//            pmsMonitorPO.setStatisticalInterval (3);
//            pmsMonitorPO.setId ("8696be1d170e05b7d848accc059f4558");
//            collect1.add (pmsMonitorPO);

            collect1.forEach (temp -> {

                Double voltage = getVoltage (temp.getVoltageLevel ( ), dictDataList);

                /*2.查询DataV
                measurement_point_id	监测点编号
                data_date	 时间
                phasic_type = A	相别
                        value_type = AVG	数据类型
                */
                /*统计间隔*/
                Integer statisticalInterval = temp.getStatisticalInterval ( );
                /*获取监测点当天的所有数据*/
                List<DataVFiveItemDTO> fiveItems = dataVInfluxdbService.getFiveItems (temp.getId (), dataDate+" "+"00:00:00",dataDate+" "+"23:59:59",statisticalInterval);

                /*过滤出有效接入分钟数量*/
                Integer count = calculateEffectiveMinute (fiveItems, pmsAbnormalRules, voltage);

                RMpIntegrityDPO rMpIntegrityDPO = new RMpIntegrityDPO ( );
                rMpIntegrityDPO.setEffectiveMinuteCount (count );
                rMpIntegrityDPO.setDataDate (tempDate);
                rMpIntegrityDPOS.add (rMpIntegrityDPO);
            });
        });
        rMpIntegrityDPOService.saveOrUpdateBatch (rMpIntegrityDPOS, 500);
    }

    /**
     * @Description: 目前只计算日表
     * @Param: [primaryGridParam]
     * @return: void
     * @Author: clam
     * @Date: 2023/2/23
     */
    private void hanlderOracleData(PrimaryGridParam primaryGridParam) {
        Integer type = primaryGridParam.getType ( );
        switch (type) {
//            case 1:
//                this.hanlderOracleYear (primaryGridParam);
//                break;
//            case 2:
//                this.hanlderOracleQtr (primaryGridParam);
//                break;
//            case 3:
//                this.hanlderOracleMonth (primaryGridParam);
//                break;
            case 5:
                this.hanlderOracleDay (primaryGridParam);
                break;
            default:
                break;
        }
    }

    @SneakyThrows
    private void hanlderOracleDay(PrimaryGridParam primaryGridParam) {

        List<String> orgIdList = primaryGridParam.getOrgIdList ( );
        String dataDate = primaryGridParam.getDataDate ( );
        List<RMpIntegrityDPO> rMpIntegrityDPOS = new ArrayList<> ( );

        //1、取出规则
        List<PmsAbnormalRules> pmsAbnormalRules = pmsAbnormalRulesMapper.selectList (null);
        //2、取出电压字典
        List<DictData> dictDataList = dicDataFeignClient.getDicDataByTypeName (DicDataTypeEnum.DEV_VOLTAGE.getName ( )).getData ( );


        final Date tempDate = new SimpleDateFormat ("yyyy-MM-dd").parse (dataDate);
        orgIdList.forEach (orgid -> {
            /*主网在运监测点*/
            List<Monitor> pmsMonitorPOS = pmsMonitorPOService.qurymeasurementRunPoints (orgid);
            List<String> mysqlIndexList = pmsMonitorPOS.stream ( ).map (Monitor::getId).collect (Collectors.toList ( ));
            if (CollectionUtil.isEmpty (mysqlIndexList)) {
                return;
            }
            /*过滤掉异常监测点*/
            QueryWrapper<RStatAbnormalDPO> rStatAbnormalDPOLambdaQueryWrapper = new QueryWrapper ( );
            rStatAbnormalDPOLambdaQueryWrapper.select ("measurementPointId").
                    in ("measurement_point_id", mysqlIndexList).
                    eq ("value_alarm", 1).
                    eq ("DATE_FORMAT( data_date ,'%Y-%m-%d')", dataDate);
            List<RStatAbnormalDPO> rStatAbnormalDPOS = rStatAbnormalDPOMapper.selectList (rStatAbnormalDPOLambdaQueryWrapper);
            List<String> collect = rStatAbnormalDPOS.stream ( ).map (RStatAbnormalDPO::getMeasurementPointId).collect (Collectors.toList ( ));
            List<Monitor> collect1 = pmsMonitorPOS.stream ( ).filter (temp -> collect.contains (temp.getId ( ))).collect (Collectors.toList ( ));
/*测试造的数据*/
//            List<PmsMonitorPO> collect1 = new ArrayList<> ();
//            PmsMonitorPO pmsMonitorPO = new PmsMonitorPO();
//            pmsMonitorPO.setVoltageLevel ("e3da890104e3c4ae1f005021411a1fd7");
//            pmsMonitorPO.setId ("666f03ed54f2288090f06d957d2d7b07");
//            pmsMonitorPO.setStatisticalInterval (3);
//            collect1.add (pmsMonitorPO);
            collect1.forEach (temp -> {

                Double voltage = getVoltage (temp.getVoltageLevel ( ), dictDataList);

                /*2.查询DataV
                measurement_point_id	监测点编号
                data_date	 时间
                phasic_type = A	相别
                        value_type = AVG	数据类型
                */

                /*获取mysql与Oracle监测点id对应关系*/

                PqLinedetailPO pqLinedetailPO = pqLinedetailPOService.getOracleIndexIdByMonitorId (temp.getId ( ));

                /*获取监测点当天的所有数据*/
                List<DataVFiveItemDTO> fiveItems = dataVOraclePOService.getFiveItems (pqLinedetailPO.getLineIndex ( ), dataDate);
                /*过滤出有效接入分钟数量*/
                Integer count = calculateEffectiveMinute (fiveItems, pmsAbnormalRules, voltage);
                /*统计间隔*/
                Integer statisticalInterval = temp.getStatisticalInterval ( );
                RMpIntegrityDPO rMpIntegrityDPO = new RMpIntegrityDPO ( );
                rMpIntegrityDPO.setEffectiveMinuteCount (count );
                rMpIntegrityDPO.setDataDate (tempDate);
                rMpIntegrityDPOS.add (rMpIntegrityDPO);
            });
        });
        rMpIntegrityDPOService.saveOrUpdateBatch (rMpIntegrityDPOS, 500);

    }

    /**
     * @Description: 3、频率在【45，55】之间；
     * 4、相电压有效值在【0.85p.u.，1.2p.u.】之间；p.u=电压等级/1.732
     * 5、线电压有效值在【0.85p.u.，1.2p.u.】之间；p.u=电压等级
     * 6、电压总谐波畸变率在【0.1%，20%】之间；
     * 7、负序电压不平衡度在【0，20%】。满足以上条件则是一条有效数据
     * @Param: [fiveItems, pmsAbnormalRules, voltage]
     * @return: java.lang.Integer
     * @Author: clam
     * @Date: 2023/2/23
     */
    private Integer calculateEffectiveMinute(List<DataVFiveItemDTO> fiveItems, List<PmsAbnormalRules> pmsAbnormalRules, Double voltage) {
        Integer result = 0;

        for (DataVFiveItemDTO fiveItem : fiveItems) {
            Double freqMax = fiveItem.getFreqMax ();
            Double freqMin = fiveItem.getFreqMin ();

            Double rmsMax = fiveItem.getRmsMax ();
            Double rmsMin = fiveItem.getRmsMin ();
            Double vThdMax = fiveItem.getVThdMax ();
            Double vThdMin = fiveItem.getVThdMin ();

            Double vUnbalanceMax = fiveItem.getVUnbalanceMax ();
            Double vUnbalanceMin = fiveItem.getVUnbalanceMin ();
            Double rmsLvrMax = fiveItem.getRmsLvrMax ();
            Double rmsLvrMin = fiveItem.getRmsLvrMin ();


            PmsAbnormalRules freqLimit = pmsAbnormalRules.stream ( ).filter (temp -> Objects.equals (temp.getTarget ( ), Param.TARGET_FREQ)).collect (Collectors.toList ( )).get (0);
            PmsAbnormalRules rmsLimit = pmsAbnormalRules.stream ( ).filter (temp -> Objects.equals (temp.getTarget ( ), Param.TARGET_RMS)).collect (Collectors.toList ( )).get (0);
            PmsAbnormalRules rms_lvrLimit = pmsAbnormalRules.stream ( ).filter (temp -> Objects.equals (temp.getTarget ( ), Param.TARGET_RMS_LVR)).collect (Collectors.toList ( )).get (0);
            PmsAbnormalRules v_thdLimit = pmsAbnormalRules.stream ( ).filter (temp -> Objects.equals (temp.getTarget ( ), Param.TARGET_V_THD)).collect (Collectors.toList ( )).get (0);
            PmsAbnormalRules v_unbalanceLimit = pmsAbnormalRules.stream ( ).filter (temp -> Objects.equals (temp.getTarget ( ), Param.TARGET_V_UNBALANCE)).collect (Collectors.toList ( )).get (0);

            if (freqLimit.getLowerLimit ( ) <= freqMin&&freqMax <= freqLimit.getUpperLimit ( ) &&
                    rmsLimit.getLowerLimit ( ) * (voltage /  1.732) <= rmsMin&&rmsMax <= rmsLimit.getUpperLimit ( ) * (voltage / 1.732) &&
                    rms_lvrLimit.getLowerLimit ( )*voltage <= rmsLvrMin&&rmsLvrMax <= rms_lvrLimit.getUpperLimit ( )*voltage &&
                    v_thdLimit.getLowerLimit ( ) <= vThdMin&&vThdMax <= v_thdLimit.getUpperLimit ( ) &&
                    v_unbalanceLimit.getLowerLimit ( ) <= vUnbalanceMin&&vUnbalanceMax <= v_unbalanceLimit.getUpperLimit ( )

            ) {
                result++;
            }
        }
        return result;
    }

    /**
     * @Description: 根据电压字典获取电压等级
     * @Param: [id, dictDataList]
     * @return: java.lang.Double
     * @Author: clam
     * @Date: 2023/2/23
     */
    private Double getVoltage(String id, List<DictData> dictDataList) {
        for (DictData dictData : dictDataList) {
            if (dictData.getId ( ).equals (id)) {
                Double result = Double.valueOf (dictData.getValue ( ));
                return result;
            }
        }
        return null;
    }
}
