package com.qmth.sop.business.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.sop.business.bean.dto.UserArchivesAllocationDto;
import com.qmth.sop.business.bean.result.*;
import com.qmth.sop.business.entity.TBCrm;
import com.qmth.sop.business.entity.TBService;
import com.qmth.sop.business.entity.TBSopInfo;
import com.qmth.sop.business.mapper.ServiceUnitAnalyseMapper;
import com.qmth.sop.business.service.ServiceUnitAnalyseService;
import com.qmth.sop.business.service.TBCrmService;
import com.qmth.sop.business.service.TBSopInfoService;
import com.qmth.sop.business.service.TBUserArchivesAllocationService;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.*;
import com.qmth.sop.common.util.FileUtil;
import com.qmth.sop.common.util.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ServiceUnitAnalyseServiceImpl extends ServiceImpl<ServiceUnitAnalyseMapper, TBService> implements ServiceUnitAnalyseService {

    @Resource
    private TBCrmService tbCrmService;

    @Resource
    private TBSopInfoService tbSopInfoService;

    @Resource
    private TBUserArchivesAllocationService tbUserArchivesAllocationService;

    @Override
    public ServiceUnitOverviewResult overview(Long serviceUnitId) {
        ServiceUnitOverviewResult result = new ServiceUnitOverviewResult();
        //派单数量
        LambdaQueryWrapper<TBCrm> crmWrapper = new LambdaQueryWrapper<>();
        crmWrapper.eq(TBCrm::getServiceId, serviceUnitId);
        int crmNum = tbCrmService.count(crmWrapper);
        result.setCrmNum(crmNum);

        //sop数量
        LambdaQueryWrapper<TBSopInfo> sopWrapper = new LambdaQueryWrapper<>();
        sopWrapper.eq(TBSopInfo::getServiceId, serviceUnitId);
        int sopNum = tbSopInfoService.count(sopWrapper);
        result.setSopNum(sopNum);

        //大区经理人数
        int leadNum = baseMapper.countLead(serviceUnitId);
        result.setLeadNum(leadNum);

        //总投入人数
        int totalPerson = baseMapper.countTotalPerson(serviceUnitId);
        result.setTotalPerson(totalPerson);

        //扫描仪数量
        List<DeviceDeliveryStatusEnum> deliveryStatusList = Arrays.asList(DeviceDeliveryStatusEnum.USING, DeviceDeliveryStatusEnum.IN, DeviceDeliveryStatusEnum.TRANSFER,
                DeviceDeliveryStatusEnum.TRANSFER_SIGN);
        int scannerNum = baseMapper.countScanner(serviceUnitId, deliveryStatusList, InOutTypeEnum.OUT);
        result.setScannerNum(scannerNum);
        return result;
    }

    @Override
    public List<ServiceUnitProgressResult> progress(Long serviceUnitId) {
        List<ServiceUnitProgressResult> progressResultList = new ArrayList<>();
        List<ServiceUnitProgressResult> sopList = baseMapper.listSopProgress(serviceUnitId);
        if (sopList != null && !sopList.isEmpty()) {
            //系统中任务状态汇总,并根据业务状态计算数量
            Map<String, List<ServiceUnitProgressResult>> map = sopList.stream().collect(Collectors.groupingBy(ServiceUnitProgressResult::getTaskName));
            Map<CrmProcessEnum, Integer> summaryMap = getCrmProcessNum(map);

            //sop的总量
            int total = summaryMap.values().stream().mapToInt(Integer::intValue).sum();
            BigDecimal totalNum = BigDecimal.valueOf(total);
            NumberFormat formatter = NumberFormat.getPercentInstance();
            formatter.setMinimumFractionDigits(2);

            //界面定义的阶段组装
            ServiceUnitProgressResult progressResult;
            CrmProcessEnum[] processValues = CrmProcessEnum.values();
            for (CrmProcessEnum process : processValues) {
                progressResult = new ServiceUnitProgressResult();
                //补充sop数量为0的阶段
                if (!summaryMap.containsKey(process)) {
                    progressResult.setProcess(process);
                    progressResult.setSopNum(0);
                    progressResultList.add(progressResult);
                } else {
                    Integer sopNum = summaryMap.get(process);
                    progressResult.setProcess(process);
                    progressResult.setSopNum(sopNum);
                    //计算占比
                    BigDecimal processNum = BigDecimal.valueOf(sopNum);
                    processNum = processNum.divide(totalNum, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
                    progressResult.setRatio(formatter.format(processNum.doubleValue() / 100));
                    progressResultList.add(progressResult);
                }
            }
        }
        return progressResultList;
    }

    @Override
    public List<ServiceUnitProvinceResult> province(Long serviceUnitId) {
        List<ServiceUnitProvinceResult> provinceResultList = new ArrayList<>();
        List<ServiceUnitProgressResult> sopList = baseMapper.listSopProgress(serviceUnitId);
        List<ServiceUnitProvinceResult> provinceCrmNumList = baseMapper.listProvinceCrmNum(serviceUnitId);

        // 各省份的派单数量
        provinceCrmNumList.forEach(province -> {
            ServiceUnitProvinceResult result = new ServiceUnitProvinceResult();
            result.setProvince(province.getProvince());
            result.setCrmNum(province.getProvinceCrmNum());

            //某个省份下所有sop数量,并按照所处阶段分组
            Map<String, List<ServiceUnitProgressResult>> processMap = sopList.stream()
                    .filter(item -> StringUtils.isNotEmpty(item.getProvinceName()) && item.getProvinceName().equals(province.getProvince()))
                    .collect(Collectors.groupingBy(ServiceUnitProgressResult::getTaskName));
            //统计界面定义的阶段,sop的数量
            Map<CrmProcessEnum, Integer> summaryMap = getCrmProcessNum(processMap);

            Integer prepareSopNum = summaryMap.get(CrmProcessEnum.PREPARE);
            Integer scanSopNum = summaryMap.get(CrmProcessEnum.SCAN);
            Integer markSopNum = summaryMap.get(CrmProcessEnum.MARK);
            Integer finalSopNum = summaryMap.get(CrmProcessEnum.FINAL);
            Integer finishSopNum = summaryMap.get(CrmProcessEnum.FINISH);

            result.setPrepareSopNum(prepareSopNum == null ? 0 : prepareSopNum);
            result.setScanSopNum(scanSopNum == null ? 0 : scanSopNum);
            result.setMarkSopNum(markSopNum == null ? 0 : markSopNum);
            result.setFinalSopNum(finalSopNum == null ? 0 : finalSopNum);
            result.setFinishSopNum(finishSopNum == null ? 0 : finishSopNum);
            Integer sopNum = result.getPrepareSopNum() + result.getScanSopNum() + result.getMarkSopNum() + result.getFinalSopNum() + result.getFinishSopNum();
            result.setSopNum(sopNum);
            Integer sopSum =  result.getScanSopNum() + result.getMarkSopNum() + result.getFinalSopNum() + result.getFinishSopNum();
            result.setSopSum(sopSum);

            provinceResultList.add(result);
        });

        return provinceResultList;
    }

    @Override
    public IPage<ProjectMonitorResult> pageSop(Page<ProjectMonitorResult> page, Long serviceUnitId, Long crmUserId, String customName, CrmProcessEnum process,
            Long leadId, String province, Long supplierId, Long coordinatorId, String type, String fieldObj) {
        List<String> processList = new ArrayList<>();
        if (process != null) {
            processList = getProcessList(process);
        }
        SopRoleTypeEnum roleType = null;
        if (supplierId != null) {
            roleType = SopRoleTypeEnum.PROJECT_MANAGER;
        }
        if (coordinatorId != null) {
            roleType = SopRoleTypeEnum.REGION_COORDINATOR;
        }

        IPage<ProjectMonitorResult> pageSop;
        // 其他
        if (supplierId == null && coordinatorId == null) {
            pageSop = baseMapper.pageSop(new Page<>(page.getCurrent(), page.getSize()), serviceUnitId, crmUserId,
                    customName, process, leadId, province, processList, type, fieldObj);
        } else { // 人力供应商、区域协调人
            pageSop = baseMapper.pageSopByUserAllocation(new Page<>(page.getCurrent(), page.getSize()), serviceUnitId, crmUserId,
                    customName, process, leadId, province, processList, supplierId, coordinatorId, roleType, type, fieldObj);
        }

        List<ProjectMonitorResult> monitorResultList = pageSop.getRecords();
        for (ProjectMonitorResult monitorResult : monitorResultList) {
            monitorResult.setProcess(CrmProcessEnum.findCrmProcessByDesc(monitorResult.getTaskName()));
            //设置区域协调人、大区经理、工程师
            List<UserArchivesAllocationDto> allocationDtoList = tbUserArchivesAllocationService.listUserArchivesAllocation(
                    monitorResult.getCrmDetailId());
            List<ProjectMonitorUserResult> coordinatorList = filterUserArchivesAllocation(allocationDtoList, SopRoleTypeEnum.REGION_COORDINATOR);
            monitorResult.setRegionCoordinator(!coordinatorList.isEmpty() ? coordinatorList.get(0) : null);
            List<ProjectMonitorUserResult> managerList = filterUserArchivesAllocation(allocationDtoList, SopRoleTypeEnum.PROJECT_MANAGER);
            monitorResult.setProjectManager(!managerList.isEmpty() ? managerList.get(0) : null);
            monitorResult.setEngineerList(filterUserArchivesAllocation(allocationDtoList, SopRoleTypeEnum.ENGINEER));
        }
        return pageSop;
    }

    @Override
    public void export(Long serviceUnitId, Long crmUserId, String customName, CrmProcessEnum process, Long leadId, String province, Long supplierId,
            Long coordinatorId, String type, String fieldObj) {
        List<String> processList = new ArrayList<>();
        if (process != null) {
            processList = getProcessList(process);
        }
        SopRoleTypeEnum roleType = null;
        if (supplierId != null) {
            roleType = SopRoleTypeEnum.PROJECT_MANAGER;
        }
        if (coordinatorId != null) {
            roleType = SopRoleTypeEnum.REGION_COORDINATOR;
        }

        List<ProjectMonitorResult> resultList;
        //其他
        if (supplierId == null && coordinatorId == null) {
            resultList = baseMapper.listSop(serviceUnitId, crmUserId, customName, process, leadId, province, processList, type, fieldObj);
        } else {// 人力供应商、区域协调人
            resultList = baseMapper.listSopByUserAllocation(serviceUnitId, crmUserId, customName, process, leadId, province, processList, supplierId,
                    coordinatorId, roleType, type, fieldObj);
        }

        //封装导出结果
        List<SopProcessExportResult> exportResultList = new ArrayList<>();
        List<SopWarnExportResult> warnExportResultList = new ArrayList<>();
        for (ProjectMonitorResult result : resultList) {
            SopInfoExportResult exportResult = getSopInfoExportResult(result);
            if (type == null) {// 预警导出
                SopProcessExportResult sopProcessExportResult = new SopProcessExportResult();
                sopProcessExportResult.setProcess(Objects.requireNonNull(CrmProcessEnum.findCrmProcessByDesc(result.getTaskName())).getTitle());
                BeanUtils.copyProperties(exportResult, sopProcessExportResult);
                exportResultList.add(sopProcessExportResult);
            } else {// 其他导出
                SopWarnExportResult sopWarnExportResult = new SopWarnExportResult();
                sopWarnExportResult.setFieldObj(Objects.requireNonNull(WarnFieldEnum.findWarnFieldEnumByTitle(result.getFieldObj())).getDesc());
                BeanUtils.copyProperties(exportResult, sopWarnExportResult);
                warnExportResultList.add(sopWarnExportResult);
            }
        }

        File fileTemp = null;
        try {
            fileTemp = SystemConstant.getFileTempVar(SystemConstant.XLSX_PREFIX);
            if (type == null) {
                EasyExcel.write(fileTemp, SopProcessExportResult.class).sheet("sop信息").doWrite(exportResultList);
            } else {
                EasyExcel.write(fileTemp, SopWarnExportResult.class).sheet("sop信息").doWrite(warnExportResultList);
            }
            HttpServletResponse response = ServletUtil.getResponse();
            FileUtil.outputFile(response, fileTemp, "sop信息.xlsx");
        } catch (IOException e) {
            throw ExceptionResultEnum.ERROR.exception(e.getMessage());
        } finally {
            if (Objects.nonNull(fileTemp)) {
                fileTemp.delete();
            }
        }
    }


    private SopInfoExportResult getSopInfoExportResult(ProjectMonitorResult result) {
        SopInfoExportResult exportResult = new SopInfoExportResult();
        exportResult.setCustomName(result.getCustomName());
        exportResult.setCrmName(result.getCrmName());
        exportResult.setCourseName(result.getCourseName());
        exportResult.setLeadName(result.getLeadName()+"-"+ result.getLeadMobile());
        List<UserArchivesAllocationDto> allocationDtoList = tbUserArchivesAllocationService.listUserArchivesAllocation(result.getCrmDetailId());
        //设置区域协调人
        List<ProjectMonitorUserResult> coordinatorList = filterUserArchivesAllocation(allocationDtoList, SopRoleTypeEnum.REGION_COORDINATOR);
        ProjectMonitorUserResult coordinator;
        if(!coordinatorList.isEmpty()) {
            coordinator = coordinatorList.get(0);
            exportResult.setRegionCoordinator(String.join("-", coordinator.getSupplierName(), coordinator.getUserName(), coordinator.getMobileNumber()));
        }

        //设置项目经理
        List<ProjectMonitorUserResult> managerList = filterUserArchivesAllocation(allocationDtoList, SopRoleTypeEnum.PROJECT_MANAGER);
        if(!managerList.isEmpty()) {
            ProjectMonitorUserResult projectManager = managerList.get(0);
            exportResult.setProjectManager(String.join("-", projectManager.getSupplierName(), projectManager.getUserName(), projectManager.getMobileNumber()));
        }

        //设置工程师
        List<ProjectMonitorUserResult> engineerList = filterUserArchivesAllocation(allocationDtoList, SopRoleTypeEnum.ENGINEER);
        if(!engineerList.isEmpty()) {
            int index = 0;
            StringBuilder engineer = new StringBuilder();
            for(ProjectMonitorUserResult engineerUser : engineerList) {
                engineer.append(String.join("-", engineerUser.getSupplierName(), engineerUser.getUserName(), engineerUser.getMobileNumber()));
                if(index < engineerList.size() - 1) {
                    engineer.append(",");
                }
                index++;
            }
            exportResult.setEngineer(engineer.toString());
        }
        return exportResult;
    }

    private List<ProjectMonitorUserResult> filterUserArchivesAllocation(List<UserArchivesAllocationDto> allocationDtoList, SopRoleTypeEnum roleType) {
        List<ProjectMonitorUserResult> monitorResultList = new ArrayList<>();
        List<UserArchivesAllocationDto> filterUserList = allocationDtoList.stream().filter(user -> user.getSopRoleType().equals(roleType)).collect(
                Collectors.toList());
        for (UserArchivesAllocationDto dto : filterUserList) {
            ProjectMonitorUserResult userResult = new ProjectMonitorUserResult();
            BeanUtils.copyProperties(dto, userResult);
            monitorResultList.add(userResult);
        }
        return monitorResultList;
    }

    private List<String> getProcessList(CrmProcessEnum process) {
        List<String> processList = new ArrayList<>();
        if (process == CrmProcessEnum.FINISH) {
            return processList;
        }
        String[] descArr = process.getDesc().split(",");
        return Arrays.asList(descArr);
    }

    private Map<CrmProcessEnum, Integer> getCrmProcessNum(Map<String, List<ServiceUnitProgressResult>> processMap) {
        Map<CrmProcessEnum, Integer> summaryMap = new HashMap<>();
        processMap.forEach((k, v) -> {
            CrmProcessEnum crmProcess = CrmProcessEnum.findCrmProcessByDesc(k);
            if (crmProcess == null)
                return;
            if (!summaryMap.containsKey(crmProcess)) {
                summaryMap.put(crmProcess, v.size());
            } else {
                summaryMap.put(crmProcess, summaryMap.get(crmProcess) + v.size());
            }
        });
        return summaryMap;
    }
}
