package cn.iocoder.yudao.module.crm.service.crmanalysis;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.ContractStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.*;
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesStatisticsRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.userlivetree.vo.UserLiveTreeListVO;
import cn.iocoder.yudao.module.crm.controller.admin.userlivetree.vo.UserLiveTreePageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.service.crmclues.CrmCluesService;
import cn.iocoder.yudao.module.crm.service.crmcontract.CrmContractService;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.ContractStatusEnum;
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.UserProductCountVO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptApiDTO;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptApiVO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;

/**
 * 业绩目标 Service 实现类
 *
 * @author yshop
 */
@Service
@Validated
public class AchievementServiceImpl implements AchievementService {

    @Resource
    private CrmAchievementMapper achievementMapper;
    @Resource
    private DeptApi deptApi;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private CrmContractMapper contractMapper;
    @Resource
    private CrmContractReceivablesMapper contractReceivablesMapper;
    @Resource
    private CrmCustomerMapper customerMapper;
    @Resource
    private CrmBusinessMapper businessMapper;
    @Resource
    private CrmCluesMapper crmCluesMapper;

    @Resource
    private BpmOAContractApi contractApi;

    @Resource
    private CrmCluesService cluesService;

    @Resource
    private BpmOAReceiptApi receiptApi;
    @Resource
    private UserLiveTreeService userLiveTreeService;
    @Resource
    private CrmContractService contractService;

    @Override
    public PageResult<UserAchieveVO> getAchievementPage(AchievementPageReqVO pageReqVO) {

        // 获取销售角色 分页列表
        PageResult<UserLiveTreeListVO> pageResult = userLiveTreeService.getUserLiveTreePage(new UserLiveTreePageReqVO());
        List<UserAchieveVO> achieveVOS = pageResult.getList().stream()
                .map(v -> new UserAchieveVO()
                        .setId(v.getUserId())
                        .setNickname(v.getNickname()))
                .collect(Collectors.toList());
        PageResult<UserAchieveVO> pageResult1 = new PageResult<>(achieveVOS, pageResult.getTotal());

        if (CollUtil.isNotEmpty(pageResult1.getList())) {

            // 获取所有用户编号列表
            List<Long> userIds = convertList(pageResult1.getList(), UserAchieveVO::getId);

            // 获取所有用户的合同统计列表
            List<ContractStatisticsDTO> contractStatisticsDTOS = contractApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
            Map<Long, ContractStatisticsDTO> contractMap = convertMap(contractStatisticsDTOS, ContractStatisticsDTO::getUserId);

            // 获取所有用户的回款统计列表
            List<ReceiptStatisticsDTO> receiptStatisticsDTOS = receiptApi.getContractStatistics(userIds, pageReqVO.getCreateTime()).getCheckedData();
            Map<Long, ReceiptStatisticsDTO> receiptMap = convertMap(receiptStatisticsDTOS, ReceiptStatisticsDTO::getUserId);

            // 获取所有用户的线索统计列表
            List<CrmCluesStatisticsRespVO> cluesStatisticsRespVOS = cluesService.getCluesStatisticsByUserIds(userIds, pageReqVO.getCreateTime());
            Map<Long, CrmCluesStatisticsRespVO> clusesMap = convertMap(cluesStatisticsRespVOS, CrmCluesStatisticsRespVO::getOwnerUserId);

            // 统计用户产品数量
            List<UserProductCountVO> userProductCountVOS = contractService.getProductCount(userIds, pageReqVO.getCreateTime());
            // -- 根据用户分组 -
            Map<Long, List<UserProductCountVO>> userProductCount = userProductCountVOS.stream()
                    .collect(Collectors.groupingBy(UserProductCountVO::getUserId));

            pageResult1.getList().forEach(v -> {
                String per = "0";
                // 设置合同数量
                v.setContractCount(contractMap.get(v.getId()) != null ? Long.valueOf(contractMap.get(v.getId()).getCount()) : 0L);
                // 设置合同金额
                v.setContractMoney(contractMap.get(v.getId()) != null ? contractMap.get(v.getId()).getMoney() : BigDecimal.ZERO);
                // 设置回款金额
                v.setReceivablesMoney(receiptMap.get(v.getId()) != null ? receiptMap.get(v.getId()).getMoney() : BigDecimal.ZERO);
                // 设置线索数量
                v.setCluesCount(clusesMap.get(v.getId()) != null ? Long.valueOf(clusesMap.get(v.getId()).getCount()) : 0L);
                // 设置转客数量
                v.setCluesToCustomerCount(clusesMap.get(v.getId()) != null ? Long.valueOf(clusesMap.get(v.getId()).getSuccessCount()) : 0L);
                // 产品列表
                v.setProductCountList(userProductCount.getOrDefault(v.getId(), Collections.emptyList()));
                // 产品数量
                int sum = v.getProductCountList().stream().mapToInt(UserProductCountVO::getNums).sum();
                v.setProductCount(sum);
                // 设置转客比率
                if (v.getCluesCount() > 0) {
                    per = NumberUtil.round(NumberUtil.div(v.getCluesToCustomerCount(), v.getCluesCount()), 2)
                            .multiply(new BigDecimal("100")).toString();
                }
                v.setCluesToCustomerPer(per);
            });
        }

        return pageResult1;
    }

    @Override
    public List<DeptAchieveVO> getDeptAchieve(AchievementPageReqVO pageReqVO) {
        List<DeptApiVO> list = deptApi.getDeptList(new DeptApiDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())).getCheckedData();
        List<DeptAchieveVO> achieveRespVOS = BeanUtils.toBean(list, DeptAchieveVO.class);
        achieveRespVOS.forEach(vo -> {
            List<AdminUserRespDTO> adminUserRespDTOS = adminUserApi.getUserListByDeptIds(CollUtil.newArrayList(vo.getId())).getCheckedData();
            List<Long> ids = CollUtil.newArrayList(-1L);
            if (!adminUserRespDTOS.isEmpty()) {
                ids = adminUserRespDTOS.stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
            }
            LambdaQueryWrapperX<CrmContractDO> wrapperX = new LambdaQueryWrapperX<>();
            wrapperX.inIfPresent(CrmContractDO::getOwnerUserId, ids)
                    .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
                    .betweenIfPresent(CrmContractDO::getCreateTime, pageReqVO.getCreateTime());
            List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapperX);
            BigDecimal contractMoney = crmContractDOS
                    .stream()
                    .map(CrmContractDO::getMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal receivablesMoney = crmContractDOS
                    .stream()
                    .map(CrmContractDO::getReturnMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            vo.setContractCount(Long.valueOf(crmContractDOS.size()));
            vo.setContractMoney(contractMoney);
            vo.setReceivablesMoney(receivablesMoney);
        });
        return achieveRespVOS;
    }


    @Override
    public List<CompletionVO> getCompletion(String relation) {
        Integer year = DateUtil.year(new Date());
        List<Long> userIds = new ArrayList<>();
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if (RelationEnum.MY.getValue().equals(relation)) {
            userIds.add(userId);
        } else if (RelationEnum.SUB.getValue().equals(relation)) {
            userIds = userLiveTreeService.getItemIdsByUserId(userId);
        }
        if (CollUtil.isEmpty(userIds)){
            return Collections.emptyList();
        }
        //合同目标
        List<CrmAchievementDO> crmAchievementDO = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
                .eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
                .in(CrmAchievementDO::getTypeId, userIds)
                .eqIfPresent(CrmAchievementDO::getConfig, ShopCommonEnum.ACH_1.getValue())
                .eqIfPresent(CrmAchievementDO::getYear, year));

        List<CompletionVO> completionVOS = new ArrayList<>();
        int i = 1;
        while (i <= 12) {
            BigDecimal targetPrice = BigDecimal.ZERO;
            BigDecimal successPrice = BigDecimal.ZERO;
            Long successCount = 0L;
            BigDecimal perPrice = BigDecimal.ZERO;
            String time = "" + year;
            if (i < 10) {
                time = time + "-0" + i;
            } else {
                time = time + "-" + i;
            }
            CompletionVO completionVO = new CompletionVO();
            completionVO.setTime(time);
            switch (i) {
                case 1: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getJanuary)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 2: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getFebruary)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 3: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getMarch)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 4: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getApril)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 5: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getMay)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 6: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getJune)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 7: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getJuly)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 8: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getAugust)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 9: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getSeptember)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 10: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getOctober)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 11: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getNovember)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
                case 12: {
                    if (crmAchievementDO != null) {
                        targetPrice = crmAchievementDO
                                .stream()
                                .map(CrmAchievementDO::getDecember)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                }
            }

            Date starTime = new Date();
            Date endTime = new Date();
            Calendar calendar = Calendar.getInstance();
            //某个月
            calendar.set(year, i - 1, 1);
            starTime = DateUtil.beginOfMonth(calendar.getTime());
            endTime = DateUtil.endOfMonth(calendar.getTime());

            LambdaQueryWrapper<CrmContractDO> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(CrmContractDO::getOwnerUserId, userIds)
                    .eq(CrmContractDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
                    .between(CrmContractDO::getOrderTime, starTime, endTime);
            List<CrmContractDO> crmContractDOS = contractMapper.selectList(wrapper);

            if (!crmContractDOS.isEmpty()) {
                successPrice = crmContractDOS
                        .stream()
                        .map(CrmContractDO::getMoney)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                successCount = Long.valueOf(crmContractDOS.size());

                if (successCount > 0) {
                    perPrice = NumberUtil.round(NumberUtil.div(successPrice, successCount), 2);
                }
            }
            completionVO.setSuccessPrice(successPrice);
            completionVO.setSuccessCount(successCount);
            completionVO.setTargetPrice(targetPrice);
            completionVO.setPerPrice(perPrice);
            completionVOS.add(completionVO);
            i++;
        }
        return completionVOS;
    }

    @Override
    public List<SalesVO> getSales(String relation) {
        Integer year = DateUtil.year(new Date());
        List<Long> userIds = new ArrayList<>();
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        if (RelationEnum.MY.getValue().equals(relation)) {
            userIds.add(userId);
        } else if (RelationEnum.SUB.getValue().equals(relation)) {
            userIds = userLiveTreeService.getItemIdsByUserId(userId);
        }
        if (CollUtil.isEmpty(userIds)){
            return Collections.emptyList();
        }
        List<SalesVO> salesVOS = new ArrayList<>();
        int i = 1;
        while (i <= 12) {
            String time = "" + year;
            if (i < 10) {
                time = time + "-0" + i;
            } else {
                time = time + "-" + i;
            }
            SalesVO salesVO = new SalesVO();
            salesVO.setTime(time);

            Date starTime = new Date();
            Date endTime = new Date();
            Calendar calendar = Calendar.getInstance();
            //某个月
            calendar.set(year, i - 1, 1);
            starTime = DateUtil.beginOfMonth(calendar.getTime());
            endTime = DateUtil.endOfMonth(calendar.getTime());

            Long cluesCount = crmCluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
                    .in(CrmCluesDO::getOwnerUserId, userIds)
                    .between(CrmCluesDO::getCreateTime, starTime, endTime));
            Long customerCount = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
                    .in(CrmCustomerDO::getOwnerUserId, userIds)
                    .between(CrmCustomerDO::getCreateTime, starTime, endTime));
            Long businessCount = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
                    .in(CrmBusinessDO::getOwnerUserId, userIds)
                    .between(CrmBusinessDO::getCreateTime, starTime, endTime));
            Long contractCount = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>()
                    .in(CrmContractDO::getOwnerUserId, userIds)
                    .between(CrmContractDO::getOrderTime, starTime, endTime));
            Long receivablesCount = contractReceivablesMapper.selectCount(new LambdaQueryWrapper<CrmContractReceivablesDO>()
                    .in(CrmContractReceivablesDO::getOwnerUserId, userIds)
                    .between(CrmContractReceivablesDO::getReturnTime, starTime, endTime));
            salesVO.setCluesCount(contractCount);
            salesVO.setCustomerCount(customerCount);
            salesVO.setBusinessCount(businessCount);
            salesVO.setContractCount(contractCount);
            salesVO.setReceivablesCount(receivablesCount);
            salesVOS.add(salesVO);
            i++;
        }
        return salesVOS;
    }
}
