package com.njcn.harmonic.service.majornetwork.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.utils.PubUtils;
import com.njcn.device.biz.pojo.po.Overlimit;
import com.njcn.device.pq.api.GeneralDeviceInfoClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.api.LineIntegrityClient;
import com.njcn.device.pq.api.OverLimitClient;
import com.njcn.device.pq.pojo.param.LineBaseQueryParam;
import com.njcn.device.pq.pojo.po.RStatIntegrityD;
import com.njcn.device.pq.pojo.vo.AreaLineInfoVO;
import com.njcn.harmonic.mapper.report.QualifiedReportMapper;
import com.njcn.harmonic.pojo.dto.FpyReportDTO;
import com.njcn.harmonic.pojo.dto.FpyTagContent;
import com.njcn.harmonic.pojo.param.QualifiedReportParam;
import com.njcn.harmonic.pojo.po.day.RStatLimitTargetDPO;
import com.njcn.harmonic.pojo.po.report.EnumPass;
import com.njcn.harmonic.service.majornetwork.QualifiedReportService;
import com.njcn.web.factory.PageFactory;
import lombok.RequiredArgsConstructor;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * pqs
 *
 * @author cdf
 * @date 2023/5/31
 */
@Service
@RequiredArgsConstructor
public class QualifiedReportServiceImpl implements QualifiedReportService {

    private static final Logger logger = LoggerFactory.getLogger(QualifiedReportServiceImpl.class);

    private final QualifiedReportMapper qualifiedReportMapper;

    private final GeneralDeviceInfoClient generalDeviceInfoClient;

    private final LineFeignClient lineFeignClient;

    private final LineIntegrityClient lineIntegrityClient;

    private final OverLimitClient overLimitClient;

    // 谐波计算的起始次数
    private static final int HARMONIC_START = 2;
    // 谐波计算的结束次数
    private static final int HARMONIC_END = 26;

    @Override
    public Page<FpyReportDTO> pageTable(QualifiedReportParam qualifiedReportParam) {
        Page<FpyReportDTO> pageResult = new Page<>(PageFactory.getPageNum(qualifiedReportParam), PageFactory.getPageSize(qualifiedReportParam));
        List<FpyReportDTO> fpyReportDTOList = new ArrayList<>();
        List<String> lineIds = generalDeviceInfoClient.deptGetRunLine(qualifiedReportParam.getDeptId()).getData();
        if (CollUtil.isEmpty(lineIds)) {
            return pageResult;
        }

        LineBaseQueryParam lineBaseQueryParam = new LineBaseQueryParam();
        lineBaseQueryParam.setLineIds(lineIds);
        lineBaseQueryParam.setSearchValue(qualifiedReportParam.getSearchValue());
        List<AreaLineInfoVO> areaLineInfoVOList = lineFeignClient.getRichLineInfo(lineBaseQueryParam).getData();
        if (CollUtil.isEmpty(areaLineInfoVOList)) {
            return pageResult;
        }
        List<String> lineNewIds = areaLineInfoVOList.stream()
                .map(AreaLineInfoVO::getLineId)
                .distinct()
                .collect(Collectors.toList());
        Map<String, AreaLineInfoVO> lineMap = areaLineInfoVOList.stream()
                .collect(Collectors.toMap(AreaLineInfoVO::getLineId, Function.identity()));

        Page<RStatLimitTargetDPO> page = qualifiedReportMapper.getLimitRateData(new Page<>(PageFactory.getPageNum(qualifiedReportParam), PageFactory.getPageSize(qualifiedReportParam)), lineNewIds, PubUtils.beginTimeToLocalDateTime(qualifiedReportParam.getBeginTime()), PubUtils.endTimeToLocalDateTime(qualifiedReportParam.getEndTime()));
        if (CollUtil.isNotEmpty(page.getRecords())) {
            List<String> realLineIds = page.getRecords().stream()
                    .map(RStatLimitTargetDPO::getLineId)
                    .distinct()
                    .collect(Collectors.toList());

            List<Map<String, Object>> dayIhMapList = qualifiedReportMapper.getLimitRateDataIHarm(lineIds, qualifiedReportParam.getBeginTime(), qualifiedReportParam.getEndTime());
            Map<String, Map<String, Object>> lineIhMap = dayIhMapList.stream()
                    .collect(Collectors.toMap(it -> it.get("MYINDEX").toString(), Function.identity()));

            List<RStatIntegrityD> rStatIntegrityList = lineIntegrityClient.getIntegrityByLineIds(realLineIds, qualifiedReportParam.getBeginTime(), qualifiedReportParam.getEndTime()).getData();
            Map<String, RStatIntegrityD> rStatIntegrityMap = rStatIntegrityList.stream()
                    .collect(Collectors.toMap(RStatIntegrityD::getLineIndex, Function.identity()));

            List<Overlimit> overLimitList = overLimitClient.getOverLimitByLineIds(realLineIds).getData();
            Map<String, Overlimit> overLimitMap = overLimitList.stream()
                    .collect(Collectors.toMap(Overlimit::getId, Function.identity()));

            for (RStatLimitTargetDPO map : page.getRecords()) {
                String lineId = map.getLineId();
                Map<String, Object> mapOverLimit = new HashMap<>();
                try {
                    BeanUtils.describe(overLimitMap.get(lineId)).forEach((key, value) -> mapOverLimit.put((String) key, value));
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    logger.error("合格率报告查询_处理Overlimit数据时发生异常", e);
                }
                //获取平均值的最大值
                Map<String, Object> lineIh = lineIhMap.get(lineId);
                FpyTagContent fpyTagContent = calAllTag(map, mapOverLimit, lineIh);

                FpyReportDTO fpyReportData = new FpyReportDTO();
                if (lineMap.containsKey(lineId)) {
                    AreaLineInfoVO areaLineInfoVO = lineMap.get(lineId);
                    BeanUtil.copyProperties(areaLineInfoVO, fpyReportData);
                    fpyReportData.setHarmDes(fpyTagContent.getPassFlag());
                    fpyReportData.setPowerDes(fpyTagContent.getContent());
                }

                if (rStatIntegrityMap.containsKey(lineId)) {
                    RStatIntegrityD rStatIntegrityD = rStatIntegrityMap.get(lineId);
                    fpyReportData.setIntegrityValue(rStatIntegrityD.getIntegrityData());
                } else {
                    fpyReportData.setIntegrityValue(3.14159f);
                }
                fpyReportDTOList.add(fpyReportData);
            }
        }
        pageResult.setRecords(fpyReportDTOList);
        pageResult.setTotal(page.getTotal());
        return pageResult;
    }

    /**
     * 计算合格率
     *
     * @param alltime    总时间
     * @param overTime   超标时间
     * @param description 描述信息
     * @return 合格率字符串
     */
    private String calculateRate(BigDecimal alltime, BigDecimal overTime, String description) {
        if (alltime.intValue() > 0 && overTime.intValue() > 0) {
            BigDecimal rate = alltime.subtract(overTime).divide(alltime, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            return description + rate.floatValue() + "%;";
        }
        return "";
    }

    /**
     * 其他指标计算
     */
    private FpyTagContent calAllTag(RStatLimitTargetDPO map, Map<String, Object> mapOverLimit, Map<String, Object> lineIhMap) {
        StrBuilder content = new StrBuilder();
        BigDecimal alltime = new BigDecimal(map.getAllTime()) ;
        BigDecimal flicketAllTime =new BigDecimal(map.getFlickerAllTime());

        FpyTagContent fpyTagContent = new FpyTagContent();
        if (alltime.intValue() > 0) {
            //频率偏差
            BigDecimal freq = new BigDecimal(map.getFreqDevOvertime());
            content.append(calculateRate(alltime, freq, "频率偏差合格率"));

            //电压偏差
            BigDecimal voltageDev = new BigDecimal(map.getVoltageDevOvertime());
            content.append(calculateRate(alltime, voltageDev, "电压偏差合格率"));

            //三项不平衡
            BigDecimal ubalance = new BigDecimal(map.getUbalanceOvertime());
            content.append(calculateRate(alltime, ubalance, "三相电压不平衡合格率"));

            //闪变
            BigDecimal flickOver = new BigDecimal(map.getFlickerOvertime());
            content.append(calculateRate(flicketAllTime, flickOver, "长时闪变合格率"));

            //电压畸变
            BigDecimal uab = new BigDecimal(map.getUaberranceOvertime());
            BigDecimal uabRate = alltime.subtract(uab).divide(alltime, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            if (uabRate.floatValue() < 95) {
                content.append("电压总畸变率").append(String.valueOf(uabRate.floatValue())).append("%;");
            }

            //计算组装谐波含电压有率
           int flagV = 0;
            for (int i = HARMONIC_START; i < HARMONIC_END; i++) {
                BigDecimal v = new BigDecimal(getUharmOvertime(i,map));
                BigDecimal hegeRate = alltime.subtract(v).divide(alltime, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                if (hegeRate.floatValue() < 95) {
                    content.append(String.valueOf(i)).append("次谐波电压含有率合格率").append(String.valueOf(hegeRate.floatValue())).append("%;");
                    flagV++;
                }
            }

            //计算组装谐波电流幅值
            int flagI = 0;
            for (int i = HARMONIC_START; i < HARMONIC_END; i++) {
                String key = "IHARM_" + i + "_OVERTIME";
                BigDecimal ih = new BigDecimal(getIharmOvertime(i,map));
                BigDecimal hegeRate = alltime.subtract(ih).divide(alltime, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                if (hegeRate.floatValue() < 95) {
                    BigDecimal maxI = (BigDecimal) lineIhMap.get(key);
                    BigDecimal overLimit = new BigDecimal(mapOverLimit.get("iharm" + i).toString());
                    content.append(String.valueOf(i)).append("次谐波电流合格率").append(String.valueOf(hegeRate.floatValue())).append("%,限值为").append(String.valueOf(overLimit.floatValue())).append("A," + "最大值为").append(String.valueOf(maxI.setScale(2, RoundingMode.HALF_UP))).append("A;");
                    flagI++;
                }
            }

            if (flagV == 0 && flagI == 0) {
                fpyTagContent.setPassFlag(EnumPass.PASS.getDescribe());
            } else if (flagV > 0 && flagI == 0) {
                fpyTagContent.setPassFlag("谐波电压");
            } else if (flagV == 0 && flagI > 0) {
                fpyTagContent.setPassFlag("谐波电流");
            } else {
                fpyTagContent.setPassFlag("谐波电压;谐波电流");
            }
            if (StrUtil.isBlank(content)) {
                fpyTagContent.setContent("合格;");
            } else {
                fpyTagContent.setContent(content.toString());
            }
        } else {
            fpyTagContent.setPassFlag("暂无数据");
            fpyTagContent.setContent("暂无数据;");
        }

        return fpyTagContent;
    }


    public Integer getUharmOvertime(int harmonicOrder, RStatLimitTargetDPO map) {
        try {
            Field field = map.getClass().getDeclaredField("uharm" + harmonicOrder + "Overtime");
            field.setAccessible(true);
            return (Integer) field.get(map);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return 0;
        }
    }

    public Integer getIharmOvertime(int harmonicOrder, RStatLimitTargetDPO map) {
        try {
            Field field = map.getClass().getDeclaredField("iharm" + harmonicOrder + "Overtime");
            field.setAccessible(true);
            return (Integer) field.get(map);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return 0;
        }
    }
}