package com.casic.missiles.service.Impl.business;

import com.casic.missiles.dto.business.board.*;
import com.casic.missiles.enums.system.ApplyFromIdEnum;
import com.casic.missiles.mapper.business.BusinessBoardMapper;
import com.casic.missiles.service.IBaseApprovalService;
import com.casic.missiles.service.business.IBusinessBoardService;
import com.casic.missiles.utils.ConvertUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @Description:
 * @Author: wangpeng
 * @Date: 2023/4/7 17:35
 */
@Service
public class IBusinessBoardServiceImpl implements IBusinessBoardService {
    @Autowired
    private BusinessBoardMapper boardMapper;
    @Resource
    private IBaseApprovalService baseApprovalService;
    @Autowired
    private ForkJoinPool forkJoinPool;

    private static List<String> workStatisticsMethodList =
            Arrays.asList("selectSamplesCompletedToday", "selectCertificatesToday",
                    "selectExpireSamplesToday", "selectSamplesThisYear",
                    "selectExpireSamplesThisYear", "selectInMeasureExpireSamplesThisYear");

    @Override
    public List<BoardWorkStatisticsResponse> workStatistics() throws ExecutionException, InterruptedException {
        //多业务表关联查询无法实现统一查询结果（不同维度），拆分查询，松耦合，方便多处组合调用
        //1、selectSamplesCompletedToday:当日检测完样品
        //计量组织表&实验室检测记录表
        //2、selectCertificatesToday:当日检定员出具证书数，证书表（出具日期）
        //计量组织表&证书报告表
        //3、selectExpireSamplesToday:当日到期样品数，实验室检测记录表关联委托书表（实验室检测记录中的委托书id个数等价于样品id个数）
        //计量组织表&实验室检测记录表&委托书表
        //4、selectSamplesThisYear:今年样品数（所有的）
        //计量组织表&实验室检测记录表&委托书样品关联表
        //协助排查注释：一个实验室存在对应一个委托书的多个样品检测；无需添加内检查询条件，在实验室检测记录中的一定是内检
        //5、selectExpireSamplesThisYear:今年超期样品总数（今年超过期的，无论现在状态如何（无需检测只发生在收发阶段也不用考虑））
        //计量组织表&实验室检测记录表&委托书表&委托书样品关联表
        //6、selectInMeasureExpireSamplesThisYear:今年超期样品总数-检测中
        //计量组织表&实验室检测记录表&委托书表&委托书样品关联表
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("workStatistics");
        List<List<BoardWorkStatisticsResponse>> transferList = new ArrayList<>();
        ForkJoinTask<List<List<BoardWorkStatisticsResponse>>> taskResponse = forkJoinPool.submit(new RecursiveTask<List<List<BoardWorkStatisticsResponse>>>() {
            @SneakyThrows
            @Override
            protected List<List<BoardWorkStatisticsResponse>> compute() {
                List<BoardRecursiveTask> taskList = new ArrayList<>();
                for (String methodName : workStatisticsMethodList) {
                    BoardRecursiveTask boardRecursiveTask = new BoardRecursiveTask(boardMapper, methodName, null);
                    taskList.add(boardRecursiveTask);
                    boardRecursiveTask.fork();
                }
                for (BoardRecursiveTask boardRecursiveTask : taskList) {
                    List<BoardWorkStatisticsResponse> list = (List<BoardWorkStatisticsResponse>) boardRecursiveTask.get();
                    transferList.add(list);
                }
                return transferList;
            }
        });
        List<BoardWorkStatisticsResponse> resultList;
        List<List<BoardWorkStatisticsResponse>> lists = taskResponse.get();
        resultList = lists.get(0);
        lists.remove(0);
        lists.forEach(list -> {
            BoardWorkStatisticsResponse boardWorkStatisticsResponse = list.get(0);
            if (Objects.nonNull(boardWorkStatisticsResponse.getCertificatesToday())) {
                resultList.forEach(dto -> {
                    dto.setCertificatesToday(list.stream().filter(c -> c.getId().equals(dto.getId())).findAny().get().getCertificatesToday());
                });
            } else if (Objects.nonNull(boardWorkStatisticsResponse.getExpireSamplesToday())) {
                resultList.forEach(dto -> {
                    dto.setExpireSamplesToday(list.stream().filter(c -> c.getId().equals(dto.getId())).findAny().get().getExpireSamplesToday());
                });
            } else if (Objects.nonNull(boardWorkStatisticsResponse.getSamplesYear())) {
                resultList.forEach(dto -> {
                    dto.setSamplesYear(list.stream().filter(c -> c.getId().equals(dto.getId())).findAny().get().getSamplesYear());
                });
            } else if (Objects.nonNull(boardWorkStatisticsResponse.getExpireSamplesYear())) {
                resultList.forEach(dto -> {
                    dto.setExpireSamplesYear(list.stream().filter(c -> c.getId().equals(dto.getId())).findAny().get().getExpireSamplesYear());
                });
            } else if (Objects.nonNull(boardWorkStatisticsResponse.getInMeasureExpireSamplesYear())) {
                resultList.forEach(dto -> {
                    dto.setInMeasureExpireSamplesYear(list.stream().filter(c -> c.getId().equals(dto.getId())).findAny().get().getInMeasureExpireSamplesYear());
                });
            }
        });
        resultList.forEach(dto -> {
            BigDecimal expire = BigDecimal.valueOf(dto.getExpireSamplesYear());
            BigDecimal total = BigDecimal.valueOf(dto.getSamplesYear());
            if (0 == (BigDecimal.ZERO).compareTo(total)) {
                dto.setExpireRate("0.00%");
            } else {
                dto.setExpireRate(expire.multiply(BigDecimal.valueOf(100)).divide(total, 2, BigDecimal.ROUND_HALF_UP).toPlainString() + "%");
            }
        });
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());

        return resultList;
    }

    @Override
    public List<BoardDeptOutputResponse> deptOutput(BoardBaseRequest request) {
        //检定样品数量
        //开始结束时间查询检定结束时间
        List<BoardBaseResponse> sampleList = boardMapper.selectStaffSamples(request);
        //出具证书数量
        //开始结束时间查询证书出具日期
        List<BoardBaseResponse> certificateList = boardMapper.selectStaffCertificates(request);
        //产值统计
        List<BoardDeptOutputResponse> actualAmountList = boardMapper.selectActualAmount(request);
        List<BoardDeptOutputResponse> samplesTotalList = boardMapper.selectSamplesTotal(request);
        List<BoardDeptOutputResponse> personalCertificatesTotalList = boardMapper.selectPersonalCertificatesTotal(request);
        List<BoardDeptOutputResponse> certificatesTotalList = boardMapper.selectCertificatesTotal(request);

        List<BoardDeptOutputResponse> resultList = ConvertUtils.sourceToTarget(sampleList, BoardDeptOutputResponse.class);
        resultList.forEach(dto -> {
            Optional<BoardBaseResponse> certOptional = certificateList.stream().filter(c -> c.getStaffId().equals(dto.getStaffId())).findAny();
            //由于证书查询sql非全部左关联，需判空
            if (Objects.nonNull(certOptional) && certOptional.isPresent()) {
                dto.setCertificates(certOptional.get().getCertificates());
            }
            Optional<BoardDeptOutputResponse> actualAmountOptional = actualAmountList.stream().filter(o -> o.getStaffId().equals(dto.getStaffId())).findAny();
            if (Objects.nonNull(actualAmountOptional) && actualAmountOptional.isPresent()) {
                Optional<BoardDeptOutputResponse> samplesTotalOptional = samplesTotalList.stream().filter(o -> o.getStaffId().equals(dto.getStaffId())).findAny();
                if (Objects.nonNull(samplesTotalOptional) && samplesTotalOptional.isPresent()) {
                    Optional<BoardDeptOutputResponse> personalCertificatesTotalOptional = personalCertificatesTotalList.stream().filter(o -> o.getStaffId().equals(dto.getStaffId())).findAny();
                    if (Objects.nonNull(personalCertificatesTotalOptional) && personalCertificatesTotalOptional.isPresent()) {
                        Optional<BoardDeptOutputResponse> certificatesTotalOptional = certificatesTotalList.stream().filter(o -> o.getStaffId().equals(dto.getStaffId())).findAny();
                        if (Objects.nonNull(certificatesTotalOptional) && certificatesTotalOptional.isPresent()) {
                            BigDecimal actualAmount = BigDecimal.valueOf(actualAmountOptional.get().getActualAmount());
                            BigDecimal samplesTotal = BigDecimal.valueOf(samplesTotalOptional.get().getSamplesTotal());
                            BigDecimal personalCertificatesTotal = BigDecimal.valueOf(personalCertificatesTotalOptional.get().getPersonalCertificatesTotal());
                            BigDecimal certificatesTotal = BigDecimal.valueOf(certificatesTotalOptional.get().getCertificatesTotal());
                            if (0 == (BigDecimal.ZERO).compareTo(samplesTotal) || 0 == (BigDecimal.ZERO).compareTo(certificatesTotal)) {
                                dto.setOutPut(0);
                            } else {
                                dto.setOutPut(actualAmount.divide(samplesTotal, 2, BigDecimal.ROUND_HALF_UP)
                                        .multiply(personalCertificatesTotal)
                                        .divide(certificatesTotal, 0, BigDecimal.ROUND_HALF_UP).intValue());
                            }
                        }
                    }
                }
            }
        });
        return resultList;
    }

    @Override
    public BoardDeptOutputListResponse deptOutputList(BoardBaseRequest request) {
        List<BoardDeptOutputResponse> deptOutputList = deptOutput(request);
        int sum = deptOutputList.stream().mapToInt(BoardDeptOutputResponse::getOutPut).sum();
        BoardDeptOutputListResponse response = new BoardDeptOutputListResponse();
        response.setOutPutTotal(sum);
        response.setList(deptOutputList);
        return response;
    }

    @Override
    public List<BoardWorkloadResponse> workload(BoardBaseRequest request) {
        Integer lastMonth = request.getMonth() - 1;
        Integer lastYear = request.getYear();
        if (0 == lastMonth) {
            lastYear = request.getYear() - 1;
            lastMonth = 12;
        }
        //检定样品数量
        List<BoardBaseResponse> sampleList = boardMapper.selectStaffSamples(request);
        //出具证书数量
        List<BoardBaseResponse> certificateList = boardMapper.selectStaffCertificates(request);
        //上月出具证书数量
        request.setYear(lastYear);
        request.setMonth(lastMonth);
        List<BoardBaseResponse> lastMonthCertificateList = boardMapper.selectStaffCertificates(request);
        List<BoardWorkloadResponse> resultList = ConvertUtils.sourceToTarget(sampleList, BoardWorkloadResponse.class);
        //较上月工作量分析
        resultList.forEach(dto -> {
            Optional<BoardBaseResponse> certOptional = certificateList.stream().filter(c -> c.getStaffId().equals(dto.getStaffId())).findAny();
            //由于证书查询sql非全部左关联，需判空
            if (Objects.nonNull(certOptional) && certOptional.isPresent()) {
                dto.setCertificates(certOptional.get().getCertificates());
            }
            Optional<BoardBaseResponse> lastMonthCertOptional = lastMonthCertificateList.stream().filter(c -> c.getStaffId().equals(dto.getStaffId())).findAny();
            if (Objects.nonNull(lastMonthCertOptional) && lastMonthCertOptional.isPresent()) {
                dto.setLastMonthCertificates(lastMonthCertOptional.get().getCertificates());
            }
            //分子
            BigDecimal numerator = BigDecimal.valueOf(dto.getCertificates() - dto.getLastMonthCertificates());
            //分母
            BigDecimal denominator = BigDecimal.valueOf(dto.getLastMonthCertificates());
            if (0 == (BigDecimal.ZERO).compareTo(denominator)) {
                dto.setCompareLastMonth("0.00%");
            } else {
                dto.setCompareLastMonth(numerator.multiply(BigDecimal.valueOf(100)).divide(denominator, 2, BigDecimal.ROUND_HALF_UP).toPlainString() + "%");
            }
        });
        return resultList;
    }

    @Override
    public List<BoardDeptComprehensiveResponse> deptComprehensive(BoardDeptComprehensiveRequest request) {
        //检定样品数量
        List<BoardDeptComprehensiveResponse> sampleList = boardMapper.selectDeptSamples(request);
        //出具证书数量
        List<BoardDeptComprehensiveResponse> certificateList = boardMapper.selectDeptCertificates(request);
        //检定样品总数
        List<BoardDeptComprehensiveResponse> sampleTotalList = boardMapper.selectDeptSamplesTotal(request);
        //超期样品总数
        List<BoardDeptComprehensiveResponse> expireSampleList = boardMapper.selectDeptExpireSamples(request);
        //部门设备总数
        List<BoardDeptComprehensiveResponse> deptDeviceList = boardMapper.selectDeptDevices(request);
        //设备过期数量，使用测量设备新建时必填的有效期判断
        List<BoardDeptComprehensiveResponse> deptExpireDeviceList = boardMapper.selectDeptExpireDevices(request);
        //设备合格数量，使用设备检定结果1:合格、2:修后合格
        List<BoardDeptComprehensiveResponse> deptPassDeviceList = boardMapper.selectDeptPassDevices(request);
        //维修设备数量，使用设备保养验收单中申请通过的就是设备维修记录（设备申请类型为9是设备检修保养验收）
        //管理员登录或未登录查询会获取所有通过的设备维修记录
        List<String> businessKeys = baseApprovalService.getPassedList(ApplyFromIdEnum.DEVICE_FIX_ACCEPTANCE.getCode());
        List<BoardDeptComprehensiveResponse> deptRepairDeviceList = boardMapper.selectDeptRepairDevices(request, businessKeys);

        //结果组装
        sampleList.forEach(dto -> {
            Optional<BoardDeptComprehensiveResponse> samplesTotalOptional = sampleTotalList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(samplesTotalOptional) && samplesTotalOptional.isPresent()) {
                dto.setSamplesTotal(samplesTotalOptional.get().getSamplesTotal());
            }
            Optional<BoardDeptComprehensiveResponse> certOptional = certificateList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(certOptional) && certOptional.isPresent()) {
                dto.setCertificates(certOptional.get().getCertificates());
            }
            Optional<BoardDeptComprehensiveResponse> expireSampleOptional = expireSampleList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(expireSampleOptional) && expireSampleOptional.isPresent()) {
                dto.setExpireSamples(expireSampleOptional.get().getExpireSamples());
            }
            //超期率
            BigDecimal expire = BigDecimal.valueOf(dto.getExpireSamples());
            BigDecimal total = BigDecimal.valueOf(dto.getSamplesTotal());
            if (0 == (BigDecimal.ZERO).compareTo(total)) {
                dto.setExpireRate("0.00%");
            } else {
                dto.setExpireRate(expire.multiply(BigDecimal.valueOf(100)).divide(total, 2, BigDecimal.ROUND_HALF_UP).toPlainString() + "%");
            }

            Optional<BoardDeptComprehensiveResponse> deptDeviceOptional = deptDeviceList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(deptDeviceOptional) && deptDeviceOptional.isPresent()) {
                dto.setDeptDevices(deptDeviceOptional.get().getDeptDevices());
            }
            //设备检定及时率
            Optional<BoardDeptComprehensiveResponse> deptExpireDeviceOptional = deptExpireDeviceList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(deptExpireDeviceOptional) && deptExpireDeviceOptional.isPresent()) {
                dto.setDeptExpireDevices(deptExpireDeviceOptional.get().getDeptExpireDevices());
            }
            BigDecimal deptDevices = BigDecimal.valueOf(dto.getDeptDevices());
            BigDecimal deptExpireDevices = BigDecimal.valueOf(dto.getDeptExpireDevices());
            //设备检定合格率
            Optional<BoardDeptComprehensiveResponse> deptPassDeviceOptional = deptPassDeviceList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(deptPassDeviceOptional) && deptPassDeviceOptional.isPresent()) {
                dto.setDeptPassDevices(deptPassDeviceOptional.get().getDeptPassDevices());
            }
            BigDecimal deptPassDevices = BigDecimal.valueOf(dto.getDeptPassDevices());
            //设备维修率
            Optional<BoardDeptComprehensiveResponse> deptRepairDeviceOptional = deptRepairDeviceList.stream().filter(c -> c.getId().equals(dto.getId())).findAny();
            if (Objects.nonNull(deptRepairDeviceOptional) && deptRepairDeviceOptional.isPresent()) {
                dto.setDeptRepairDevices(deptRepairDeviceOptional.get().getDeptRepairDevices());
            }
            BigDecimal deptRepairDevices = BigDecimal.valueOf(dto.getDeptRepairDevices());
            if (0 == (BigDecimal.ZERO).compareTo(deptDevices)) {
                dto.setDeviceTimelyRate("0.00%");
                dto.setDeviceQualifyRate("0.00%");
                dto.setDeviceRepairRate("0.00%");
            } else {
                dto.setDeviceTimelyRate(deptExpireDevices.multiply(BigDecimal.valueOf(100)).divide(deptDevices, 2, BigDecimal.ROUND_HALF_UP).toPlainString() + "%");
                dto.setDeviceQualifyRate(deptPassDevices.multiply(BigDecimal.valueOf(100)).divide(deptDevices, 2, BigDecimal.ROUND_HALF_UP).toPlainString() + "%");
                dto.setDeviceRepairRate(deptRepairDevices.multiply(BigDecimal.valueOf(100)).divide(deptDevices, 2, BigDecimal.ROUND_HALF_UP).toPlainString() + "%");
            }
        });
        return sampleList;
    }
}
