package com.energy.manage.service.service.homepage.impl;

import com.energy.manage.common.enums.TypeRelationEnum;
import com.energy.manage.common.po.analysis.AnalysisResultPo;
import com.energy.manage.common.po.windrelation.WindRelationPO;
import com.energy.manage.service.constant.analysis.AnalysisStatusConstants;
import com.energy.manage.service.domain.vo.analysis.AnalysisDiagramRelationVo;
import com.energy.manage.service.domain.vo.analysis.AnalysisGeneralFileVo;
import com.energy.manage.service.domain.vo.analysis.AnalysisOptionRecordsVo;
import com.energy.manage.service.domain.vo.analysis.AnalysisResultVo;
import com.energy.manage.service.domain.vo.homepage.FloatingWindowInfoVo;
import com.energy.manage.service.domain.vo.homepage.HomePageVo;
import com.energy.manage.service.domain.vo.homepage.WaitTaskVo;
import com.energy.manage.service.domain.vo.system.SysOrganizationAuthVo;
import com.energy.manage.service.domain.vo.windenginegroup.WindEngineGroupPageVo;
import com.energy.manage.service.domain.vo.windexceptioncount.WindExceptionCountVo;
import com.energy.manage.service.domain.vo.windfield.WindFieldVo;
import com.energy.manage.service.mappers.analysis.AnalysisDiagramRelationMapper;
import com.energy.manage.service.mappers.analysis.AnalysisGeneralFileMapper;
import com.energy.manage.service.mappers.analysis.AnalysisOptionRecordsMapper;
import com.energy.manage.service.mappers.analysis.AnalysisResultMapper;
import com.energy.manage.service.mappers.system.SysOrganizationAuthMapper;
import com.energy.manage.service.mappers.windenginegroup.WindEngineGroupMapper;
import com.energy.manage.service.mappers.windexceptioncount.WindExceptionCountMapper;
import com.energy.manage.service.mappers.windfield.WindFieldMapper;
import com.energy.manage.service.mappers.windrelation.WindRelationMapper;
import com.energy.manage.service.service.homepage.HomePageService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author chy
 * @date 2024/6/13 14:03
 * @desc
 */
@Service
public class HomePageServiceImpl implements HomePageService {


    @Autowired
    private WindRelationMapper relationMapper;

    @Autowired
    private AnalysisResultMapper analysisResultMapper;

    @Autowired
    private WindExceptionCountMapper exceptionCountMapper;

    @Autowired
    private AnalysisOptionRecordsMapper analysisOptionRecordsMapper;

    @Autowired
    private SysOrganizationAuthMapper authMapper;

    @Autowired
    private AnalysisGeneralFileMapper generalFileMapper;

    @Autowired
    private AnalysisDiagramRelationMapper diagramRelationMapper;

    @Autowired
    private WindFieldMapper windFieldMapper;

    @Autowired
    private WindEngineGroupMapper windEngineGroupMapper;


    /**
     * 驾驶舱首页查询
     * @param codeNumber
     * @param codeType
     */
    @Override
    public HomePageVo queryStatistics(Integer roleId,
                                      String codeNumber,
                                      String codeType,
                                      String startTime,
                                      String endTime) {
        //返回实体对象
        HomePageVo homePageVo = new HomePageVo();
        //风场
        List<String> fieldCodes = new ArrayList<>();
        //根据类型判断获取风场code
        if(codeType.equals(TypeRelationEnum.COMPANY_NUMBER.getCode())){
            filterAuthFieldCode(roleId,Arrays.asList(codeNumber), fieldCodes);
        }else{
            fieldCodes.add(codeNumber);
        }
        //如果风场code为空，则不设置
        if(CollectionUtils.isEmpty(fieldCodes)){
            return homePageVo;
        }
        //设置未分析、分析中、已分析数目
        setAnalysisCount(homePageVo,fieldCodes,startTime,endTime);
        //设置异常数、异常信息
        setErrCountAndInfo(homePageVo,fieldCodes,startTime,endTime);
        return homePageVo;
    }

    /**
     * 获取操作记录
     * @param codeNumber
     * @param codeType
     * @return
     */
    @Override
    public List<AnalysisOptionRecordsVo> queryOptionRecords(Integer roleId,
                                                            String codeNumber,
                                                            String codeType,
                                                            String startTime,
                                                            String endTime){
        List<AnalysisOptionRecordsVo> voList = new ArrayList<>();
        //风场
        List<String> fieldCodes = new ArrayList<>();
        //根据类型判断获取风场code
        if(codeType.equals(TypeRelationEnum.COMPANY_NUMBER.getCode())){
            filterAuthFieldCode(roleId,Arrays.asList(codeNumber), fieldCodes);
        }else{
            fieldCodes.add(codeNumber);
        }
        //如果风场code为空，则不设置
        if(CollectionUtils.isEmpty(fieldCodes)){
            return voList;
        }
        return analysisOptionRecordsMapper.selectAllByTimeDesc(fieldCodes,startTime,endTime);
    }


    /**
     * 获取悬浮窗信息
     * @param batchCode
     * @return
     */
    @Override
    public FloatingWindowInfoVo queryFloatingWindowInfo(String batchCode, String fieldCode){
        FloatingWindowInfoVo floatingWindowInfoVo = new FloatingWindowInfoVo();
        //设置装机容量
        WindFieldVo windFieldVo = windFieldMapper.selectByCodeNumber(fieldCode);
        floatingWindowInfoVo.setRatedCapacityNumber(windFieldVo == null ? "0" : doubleDivide(windFieldVo.getRatedCapacityNumber(),1000D));
        //设置风机数量
        List<WindEngineGroupPageVo> windEngineGroupPageVos = windEngineGroupMapper.selectWindEngineGroupListByFieldCode(fieldCode);
        floatingWindowInfoVo.setEngineTotalCount(windEngineGroupPageVos.size());
        //设置分析信息
        if(StringUtils.isNotBlank(batchCode)){
            //设置分析时间 数据时间范围
            AnalysisResultPo analysisResultPo = analysisResultMapper.selectByBatchCode(batchCode);
            BeanUtils.copyProperties(analysisResultPo,floatingWindowInfoVo);
            //设置分析类型数目
            Set<String> analysisGeneralTypes = generalFileMapper.selectByBatchCode(batchCode).stream()
                                                                        .map(AnalysisGeneralFileVo::getAnalysisTypeCode)
                                                                        .collect(Collectors.toSet());
            Set<String> analysisDeliayTypes = diagramRelationMapper.selectByBatchCode(batchCode).stream()
                                                                        .map(AnalysisDiagramRelationVo :: getAnalysisTypeCode)
                                                                        .collect(Collectors.toSet());
            analysisGeneralTypes.addAll(analysisDeliayTypes);
            floatingWindowInfoVo.setAnalysisTypeCount(analysisGeneralTypes.size());
        }
        return floatingWindowInfoVo;
    }

    /**
     * double计算(四舍五入)
     * @param dividend
     * @param divisor
     * @return
     */
    private String doubleDivide(Double dividend, Double divisor){
        BigDecimal dividendBigDecimal = new BigDecimal(dividend);
        BigDecimal divisorBigDecimal = new BigDecimal(divisor);
        return dividendBigDecimal.divide(divisorBigDecimal,BigDecimal.ROUND_HALF_UP).toString();
    }

    @Override
    public WaitTaskVo getWaitTask(Integer roleId) {
        return authMapper.selectFieldAnalysisResultByroleId(roleId);
    }

    @Override
    public List<AnalysisResultPo> getAnalysisResultStateList(Integer roleId) {
        List<AnalysisResultPo> list = authMapper.selectWindRelationByAnalysisState(roleId);
        return list;
    }

    @Override
    public List<AnalysisResultPo> getAnalysisResultErrStateList(Integer roleId) {
        List<AnalysisResultPo> list = authMapper.selectWindRelationByErrState(roleId);
        return list;
    }

    /**
     * 根据角色权限过滤fieldCode
     * @param roleId
     * @param companyCodes
     * @param fieldCodes
     */
    private void filterAuthFieldCode(Integer roleId, List<String> companyCodes, List<String> fieldCodes){
        getFieldCodeList(companyCodes, fieldCodes);
        List<SysOrganizationAuthVo> vos = authMapper.selectByRoleId(roleId);
        List<String> codes = vos.stream().map(SysOrganizationAuthVo::getCodeNumber).collect(Collectors.toList());
        fieldCodes.retainAll(codes);
    }

    /**
     * 递归获取风场code
     * @param companyCodes
     * @param fieldCodes
     */
    private void getFieldCodeList(List<String> companyCodes, List<String> fieldCodes){
        if(CollectionUtils.isEmpty(companyCodes)){
            return;
        }
        List<WindRelationPO> relationPos = relationMapper.selectByCodeNumber(companyCodes);
        List<String> companyCodeList = new ArrayList<>();
        relationPos.stream().forEach(item -> {
            if(TypeRelationEnum.WIND_FIELD_NUMBER.getCode().equals(item.getType())){
                fieldCodes.add(item.getCodeNumber());
            }
            if(TypeRelationEnum.COMPANY_NUMBER.getCode().equals(item.getType())){
                companyCodeList.add(item.getCodeNumber());
            }
        });
        getFieldCodeList(companyCodeList,fieldCodes);
    }

    /**
     * 分析数设置
     * @param homePageVo
     * @param fieldCodes
     * @param startTime
     * @param endTime
     */
    private void setAnalysisCount(HomePageVo homePageVo,List<String> fieldCodes,String startTime,String endTime){
        List<AnalysisResultVo> resultVos = analysisResultMapper.selectLastBatchResultByFieldCode(fieldCodes,startTime,endTime);
        Integer total = fieldCodes.size();
        if(CollectionUtils.isEmpty(resultVos)){
            //分析结果为空的时候证明没有风场没有进行分析
            homePageVo.setNoAnalysisCount(total);
            return ;
        }
        resultVos.stream().forEach(item -> {
            Integer analysisState = item.getAnalysisState();
            //分析中
            if(analysisState.equals(AnalysisStatusConstants.ANALYSISING_STATE)){
                homePageVo.analysisingCountAdd();
            }
            //分析完成
            if(analysisState.equals(AnalysisStatusConstants.ANALYSISED_STATE)){
                homePageVo.analysisedCountAdd();
            }
        });
        //设置未分析
        homePageVo.setNoAnalysisCount(total - homePageVo.getAnalysisedCount() - homePageVo.getAnalysisingCount());
    }

    /**
     * 设置异常数
     * @param homePageVo
     * @param fieldCodes
     * @param startTime
     * @param endTime
     */
    public void setErrCountAndInfo(HomePageVo homePageVo, List<String> fieldCodes, String startTime, String endTime){
        List<WindExceptionCountVo> exceptionCounts = exceptionCountMapper.selectByfieldCodes(fieldCodes, startTime, endTime);
        //风机异常数
        Set<String> engineCodes = new HashSet<>();
        //处理异常数
        AtomicInteger handleErrCount = new AtomicInteger(0);
        //当月异常数
        AtomicInteger errCountCurrentMonth = new AtomicInteger(0);
        exceptionCounts.stream().forEach(item -> {
            //设置总异常数
            homePageVo.setErrCounrt(homePageVo.getErrCounrt() + item.getErrCount());
            //异常处理数
            handleErrCount.addAndGet(item.getHandleErrCount());
            //设备异常数
            engineCodes.add(item.getEngineCode());
            //叠加当月异常数
            if(isCurrentMonth(item.getCreateTime())){
                errCountCurrentMonth.addAndGet(item.getErrCount());
            }
        });
        //设置未处理异常数
        homePageVo.setErrCountNotDeal(homePageVo.getErrCounrt() - handleErrCount.get());
        //设置当月异常数
        homePageVo.setErrCountInCurrentMonth(errCountCurrentMonth.get());
        //设置异常设备数
        homePageVo.setErrDeviceCount(engineCodes.size());
        //过滤属性风机编号相同的元素
        exceptionCounts = exceptionCounts.stream().distinct().filter(distinctByKey(WindExceptionCountVo :: getEngineCode)).collect(Collectors.toList());
        homePageVo.setErrList(exceptionCounts);
    }

    /**
     * 过滤器
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static  <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor){
        Map<Object,Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 判断是否是当月
     * @param sourceTime
     * @return
     */
    private Boolean isCurrentMonth(Date sourceTime){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sourceTime);
        Calendar now = Calendar.getInstance();
        return calendar.get(Calendar.MONTH) == now.get(Calendar.MONTH);
    }
}
