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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
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.DeptTypeEnum;
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.BpmOAContractDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.contract.BpmOAContractVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmachievement.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmachievement.CrmAchievementDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.FlowStepEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserPageApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
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.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.ACHIEVEMENT_NOT_EXISTS;


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

    @Resource
    private CrmAchievementMapper achievementMapper;
    @Resource
    private DeptApi deptApi;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private BpmOAContractApi contractApi;

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


    @Override
    public void createAchievement(DeptAchieveSaveVO createReqVO) {

        //计算年目标
        List<BigDecimal> bigDecimals = Arrays.asList(
                createReqVO.getAchievementRespVO().getJanuary(), createReqVO.getAchievementRespVO().getFebruary(),
                createReqVO.getAchievementRespVO().getMarch(), createReqVO.getAchievementRespVO().getApril(),
                createReqVO.getAchievementRespVO().getMay(), createReqVO.getAchievementRespVO().getJune(),
                createReqVO.getAchievementRespVO().getJuly(), createReqVO.getAchievementRespVO().getAugust(),
                createReqVO.getAchievementRespVO().getSeptember(), createReqVO.getAchievementRespVO().getOctober(),
                createReqVO.getAchievementRespVO().getNovember(), createReqVO.getAchievementRespVO().getDecember()
        );
        BigDecimal yearTarget = bigDecimals.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        createReqVO.getAchievementRespVO().setYeartarget(yearTarget);

        if (createReqVO.getId() == 0) {

            List<CrmAchievementDO> achievements;
            //批量
            if (FlowStepEnum.TYPE_3.getValue().equals(createReqVO.getAchievementRespVO().getType())) {
                // 获取所有营销部门列表
                List<DeptRespDTO> list = deptApi.getDeptListByType(DeptTypeEnum.SALE_DEPT.getValue()).getCheckedData();
                // 获取 插入/更新信息列表
                achievements = list.stream().map(item -> {
                    CrmAchievementDO achievement = BeanUtils.toBean(createReqVO.getAchievementRespVO(), CrmAchievementDO.class);
                    achievement.setTypeId(item.getId());
                    achievement.setName(item.getName());
                    return achievement;
                }).collect(Collectors.toList());

            } else {
                List<AdminUserRespDTO> list = adminUserApi.getUserListAll(1, null, CommonStatusEnum.ENABLE.getStatus(), "sale").getCheckedData();
                // 获取 插入/更新信息列表
                achievements = list.stream().map(item -> {
                    CrmAchievementDO achievement = BeanUtils.toBean(createReqVO.getAchievementRespVO(), CrmAchievementDO.class);
                    achievement.setTypeId(item.getId());
                    achievement.setName(item.getNickname());
                    return achievement;
                }).collect(Collectors.toList());
            }

            // 批量插入操作
            saveAchievementBatch(createReqVO, achievements);
        } else {
            //单个操作
            if (FlowStepEnum.TYPE_3.getValue().equals(createReqVO.getAchievementRespVO().getType())) {
                createReqVO.setName(createReqVO.getName());
            } else {
                createReqVO.setName(createReqVO.getNickname());
            }
            saveAchievement(createReqVO);
        }
    }

    /**
     * 添加或者更新
     *
     * @param createReqVO
     */
    private void saveAchievement(DeptAchieveSaveVO createReqVO) {
        // 插入
        CrmAchievementDO achievement = BeanUtils.toBean(createReqVO.getAchievementRespVO(), CrmAchievementDO.class);
        achievement.setTypeId(createReqVO.getId());
        achievement.setName(createReqVO.getName());
        LambdaQueryWrapperX<CrmAchievementDO> wrapper = new LambdaQueryWrapperX<>();
        wrapper.eq(CrmAchievementDO::getType, achievement.getType())
                .eq(CrmAchievementDO::getTypeId, achievement.getTypeId())
                .eq(CrmAchievementDO::getConfig, achievement.getConfig())
                .eq(CrmAchievementDO::getYear, achievement.getYear());
        CrmAchievementDO achievementOld = achievementMapper.selectOne(wrapper);

        if (achievementOld == null) {
            achievementMapper.insert(achievement);
        } else {
            achievement.setId(achievementOld.getId());
            achievementMapper.updateById(achievement);
        }
    }

    /**
     * 批量插入操作
     *
     * @param createReqVO  更新信息
     * @param achievements 更新信息
     */
    private void saveAchievementBatch(DeptAchieveSaveVO createReqVO, List<CrmAchievementDO> achievements) {

        if (CollectionUtil.isNotEmpty(achievements)) {

            List<Long> typeIds = convertList(achievements, CrmAchievementDO::getId);
            // 判断业绩数据是否已存在
            List<CrmAchievementDO> achievementOld = achievementMapper.selectAchievementList(createReqVO, typeIds);
            if (CollectionUtil.isEmpty(achievementOld)) {

                achievementMapper.insertBatch(achievements);
            } else {

                // 获取之前业绩数据Map
                Map<Long, CrmAchievementDO> oldMap = convertMap(achievementOld, CrmAchievementDO::getTypeId);
                // 设置ID
                achievements.forEach(item -> {
                    item.setId(oldMap.get(item.getTypeId()).getId());
                });

                achievementMapper.updateBatch(achievements);
            }
        }
    }

    @Override
    public void updateAchievement(CrmAchievementSaveReqVO updateReqVO) {
        // 校验存在
        validateAchievementExists(updateReqVO.getId());
        // 更新
        CrmAchievementDO updateObj = BeanUtils.toBean(updateReqVO, CrmAchievementDO.class);
        achievementMapper.updateById(updateObj);
    }

    @Override
    public void deleteAchievement(Long id) {
        // 校验存在
        validateAchievementExists(id);
        // 删除
        achievementMapper.deleteById(id);
    }

    private void validateAchievementExists(Long id) {
        if (achievementMapper.selectById(id) == null) {
            throw exception(ACHIEVEMENT_NOT_EXISTS);
        }
    }

    @Override
    public CrmAchievementDO getAchievement(Long id) {
        return achievementMapper.selectById(id);
    }

    @Override
    public PageResult<UserAchieveRespVO> getAchievementPage(CrmAchievementPageReqVO pageReqVO) {

        // 设置用户查询条件
        AdminUserPageApiDTO userPageReqVO = new AdminUserPageApiDTO();
        userPageReqVO.setPageNo(pageReqVO.getPageNo());
        userPageReqVO.setPageSize(pageReqVO.getPageSize());
        userPageReqVO.setNickname(pageReqVO.getName());
        userPageReqVO.setRoleCodes("sale"); // 设置查询用户的角色类型

        // 查询用户分页列表
        PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(userPageReqVO).getCheckedData();
        PageResult<UserAchieveRespVO> userPage = BeanUtils.toBean(pageResult, UserAchieveRespVO.class);
        if (CollectionUtil.isNotEmpty(pageResult.getList())) {

            // 查询用户的 业绩信息
            List<Long> typeIds = convertList(userPage.getList(), UserAchieveRespVO::getId);
            List<CrmAchievementDO> crmAchievementDOS = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
                    .eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
                    .eq(CrmAchievementDO::getConfig, pageReqVO.getConfig())
                    .in(CrmAchievementDO::getTypeId, typeIds)
                    .eq(CrmAchievementDO::getYear, pageReqVO.getYear())
            );
            // 获得业绩信息Map
            Map<Long, CrmAchievementDO> achievementMap = convertMap(crmAchievementDOS, CrmAchievementDO::getTypeId);

            userPage.getList().forEach(item -> {

                CrmAchievementDO crmAchievementDO = achievementMap.get(item.getId());
                if (crmAchievementDO == null) {
                    crmAchievementDO = CrmAchievementDO.builder()
                            .january(BigDecimal.ZERO).february(BigDecimal.ZERO).march(BigDecimal.ZERO)
                            .april(BigDecimal.ZERO).may(BigDecimal.ZERO).june(BigDecimal.ZERO)
                            .july(BigDecimal.ZERO).august(BigDecimal.ZERO).september(BigDecimal.ZERO)
                            .october(BigDecimal.ZERO).november(BigDecimal.ZERO).december(BigDecimal.ZERO)
                            .yeartarget(BigDecimal.ZERO)
                            .build();
                }

                item.setAchievementRespVO(BeanUtils.toBean(crmAchievementDO, CrmAchievementRespVO.class));
            });
        }

        return userPage;
    }

    @Override
    public List<DeptAchieveRespVO> getDeptAchieve(Integer config, Integer year) {

        // 获取销售部门列表
        List<DeptRespDTO> list = deptApi.getDeptListByType(DeptTypeEnum.SALE_DEPT.getValue()).getCheckedData();
        // 获取部门编号列表
        List<Long> typeIds = list.stream().map(DeptRespDTO::getId).distinct().collect(Collectors.toList());

        // 获取部门业绩列表
        List<CrmAchievementDO> crmAchievementDOS = achievementMapper.selectAchievementList(config, year, typeIds);
        Map<Long, List<CrmAchievementDO>> map = crmAchievementDOS.stream().collect(Collectors.groupingBy(CrmAchievementDO::getTypeId));

        List<DeptAchieveRespVO> achieveRespVOS = BeanUtils.toBean(list, DeptAchieveRespVO.class);
        achieveRespVOS.forEach(vo -> {
            List<CrmAchievementDO> doList = map.get(vo.getId());
            CrmAchievementDO crmAchievementDO = null;
            if (CollUtil.isNotEmpty(doList)) {
                crmAchievementDO = doList.get(0);
            }
            if (crmAchievementDO == null) {
                crmAchievementDO = CrmAchievementDO.builder()
                        .january(BigDecimal.ZERO).february(BigDecimal.ZERO).march(BigDecimal.ZERO)
                        .april(BigDecimal.ZERO).may(BigDecimal.ZERO).june(BigDecimal.ZERO)
                        .july(BigDecimal.ZERO).august(BigDecimal.ZERO).september(BigDecimal.ZERO)
                        .october(BigDecimal.ZERO).november(BigDecimal.ZERO).december(BigDecimal.ZERO)
                        .yeartarget(BigDecimal.ZERO)
                        .build();
            }
            vo.setAchievementRespVO(BeanUtils.toBean(crmAchievementDO, CrmAchievementRespVO.class));
        });
        return achieveRespVOS;
    }

    @Override
    public AchieveCountRespVO getCount(Integer type, Integer year, Integer month, Long userId) {

        // 获取当前登录用户编号
        List<Long> userIds = new ArrayList<>();
        Long typeId = SecurityFrameworkUtils.getLoginUserId();

        if (FlowStepEnum.TYPE_2.getValue().equals(type)) {
            userIds.add(typeId);
        } else if (FlowStepEnum.TYPE_3.getValue().equals(type)) {
            //部门
            String deptId = Objects.requireNonNull(SecurityFrameworkUtils.getLoginUser()).getInfo().get(SecurityFrameworkUtils.INFO_KEY_DEPT_ID);
            typeId = deptId == null ? null : Long.valueOf(deptId);
            List<AdminUserApiVO> adminUserDOS = new ArrayList<>();
            if (typeId != null) {
                adminUserDOS = adminUserApi.getUserList(new AdminUserApiDTO().setDeptId(typeId).setNextDept(1)).getCheckedData();
            }
            userIds = adminUserDOS.stream().map(AdminUserApiVO::getId).collect(Collectors.toList());
        } else {
            if (userId != null) {
                userIds.add(userId);
            } else {
                //下属
                userIds = userLiveTreeService.getItemIdsByUserId(typeId);
            }
        }
        Date starTime = new Date();
        Date endTime = new Date();
        Calendar calendar = Calendar.getInstance();
        if (month == 0) {
            //全年
            calendar.set(year, 1, 1);
            starTime = DateUtil.beginOfYear(calendar.getTime());
            endTime = DateUtil.endOfYear(calendar.getTime());
        } else {
            //某个月
            calendar.set(year, month - 1, 1);
            starTime = DateUtil.beginOfMonth(calendar.getTime());
            endTime = DateUtil.endOfMonth(calendar.getTime());
        }

        List<CrmAchievementDO> achievementDOS = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
                .eq(CrmAchievementDO::getType, type)
                .eq(CrmAchievementDO::getTypeId, typeId)
                .eqIfPresent(CrmAchievementDO::getYear, year));
        Map<Integer, CrmAchievementDO> achievementMap = convertMap(achievementDOS, CrmAchievementDO::getConfig);
        // 合同目标
        CrmAchievementDO crmAchievementDO = achievementMap.get(ShopCommonEnum.ACH_1.getValue());
        // 回款目标
        CrmAchievementDO crmAchievementDO2 = achievementMap.get(ShopCommonEnum.ACH_2.getValue());

        // 获取合同信息
        List<BpmOAContractDTO> contractDTOS = contractApi.getContractList(new BpmOAContractVO()
                .setContractType(BpmOAContractVO.SALE_CONTRACT)
                .setUserId(userIds)
                .setStarTime(starTime)
                .setEndTime(endTime)).getCheckedData();

        BigDecimal contractSuccessMoney = BigDecimal.ZERO;
        if (CollectionUtil.isNotEmpty(contractDTOS)) {
            // 累加合同金额
            contractSuccessMoney = contractDTOS.stream()
                    .map(BpmOAContractDTO::getContractMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        // 获取回款信息
        List<BpmOAReceiptDTO> receiptDTOS = receiptApi.getReceiptList(new BpmOAReceiptVO()
                .setUserId(userIds)
                .setStarTime(starTime)
                .setEndTime(endTime)).getCheckedData();

        BigDecimal receivablesSuccessMoney = BigDecimal.ZERO;
        if (CollectionUtil.isNotEmpty(receiptDTOS)) {
            receivablesSuccessMoney = receiptDTOS
                    .stream()
                    .map(BpmOAReceiptDTO::getMoney)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        BigDecimal contractMoney = BigDecimal.ZERO;
        BigDecimal receivablesMoney = BigDecimal.ZERO;
        String contractPer = "0";
        String receivablesPer = "0";
        switch (month) {
            case 0: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getYeartarget();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getYeartarget();
                }
            }
            case 1: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getJanuary();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getJanuary();
                }
            }
            case 2: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getFebruary();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getFebruary();
                }
            }
            case 3: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getMarch();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getMarch();
                }
            }
            case 4: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getApril();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getApril();
                }
            }
            case 5: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getMay();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getMay();
                }
            }
            case 6: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getJune();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getJune();
                }
            }
            case 7: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getJuly();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getJuly();
                }
            }
            case 8: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getAugust();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getAugust();
                }
            }
            case 9: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getSeptember();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getSeptember();
                }
            }
            case 10: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getOctober();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getOctober();
                }
            }
            case 11: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getNovember();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getNovember();
                }
            }
            case 12: {
                if (crmAchievementDO != null) {
                    contractMoney = crmAchievementDO.getDecember();
                }
                if (crmAchievementDO2 != null) {
                    receivablesMoney = crmAchievementDO2.getDecember();
                }
            }
        }
        if (contractMoney.compareTo(BigDecimal.ZERO) > 0) {
            contractPer = NumberUtil.round(NumberUtil.div(contractSuccessMoney, contractMoney), 2)
                    .multiply(new BigDecimal("100")).toString();
        }
        if (receivablesMoney.compareTo(BigDecimal.ZERO) > 0) {
            receivablesPer = NumberUtil.round(NumberUtil.div(receivablesSuccessMoney, receivablesMoney), 2)
                    .multiply(new BigDecimal("100")).toString();
        }

        return AchieveCountRespVO.builder()
                .contractMoney(contractMoney)
                .contractSuccessMoney(contractSuccessMoney)
                .receivablesMoney(receivablesMoney)
                .receivablesSuccessMoney(receivablesSuccessMoney)
                .contractPer(contractPer)
                .receivablesPer(receivablesPer)
                .build();
    }
}
