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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
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.dataobject.crmcustomercontacts.CrmCustomerContactsDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
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.dal.mysql.crmcustomercontacts.CrmCustomerContactsMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
import cn.iocoder.yudao.module.crm.service.crmoperatelog.CrmOperatelogService;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.CustomerTypesEnum;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS;

/**
 * 客户 Service 实现类
 *
 * @author yshop
 */
@Service
@Validated
public class CrmCustomerServiceImpl implements CrmCustomerService {

    @Resource
    private CrmCustomerMapper customerMapper;
    @Resource
    private CrmOperatelogService crmOperatelogService;
    @Resource
    private CrmCustomerContactsMapper customerContactsMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private SmsSendApi smsSendApi;
    @Resource
    private MailSendApi mailSendApi;
    @Resource
    private CrmRecordMapper crmRecordMapper;
    @Resource
    private CrmBusinessMapper crmBusinessMapper;
    @Resource
    private CrmContractMapper contractMapper;
    @Resource
    private CrmContractReceivablesMapper contractReceivablesMapper;
    @Resource
    private UserLiveTreeService userLiveTreeService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCustomer(CrmCustomerSaveReqVO createReqVO) {
        // 插入
        // 判断客户名称是否唯一
        List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(createReqVO.getName());
        if (CollUtil.isNotEmpty(repeatOwnerUserNameList) && createReqVO.getRepeatConfirmationFlag() == 0) {
            List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
            throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?"));
        }
        CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
        customer.setCollectTime(LocalDateTime.now());
        customer.setFollowTime(LocalDateTime.now());
        // 由于这里是 size 而排序是从0开始的 所以这里递增一个直接用size即可
        customer.setSortNum(repeatOwnerUserNameList.size());
        customer.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        customerMapper.insert(customer);

        //创建联系人
        CrmCustomerContactsDO crmCustomerContactsDO = CrmCustomerContactsDO.builder()
                .customerId(customer.getId())
                .ownerUserId(SecurityFrameworkUtils.getLoginUserId())
                .name(createReqVO.getName())
                .mobile(createReqVO.getMobile())
                .telephone(createReqVO.getTelephone())
                .remark(createReqVO.getRemark())
                .wechat(createReqVO.getWeixin())
                .build();
        customerContactsMapper.insert(crmCustomerContactsDO);


        //插入日志
        crmOperatelogService.createLog("添加客户", customer.getId(), 0L, 0L);
        // 返回
        return customer.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
        // 校验存在
        CrmCustomerDO customerDO = validateCustomerExists(updateReqVO.getId());
        List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(updateReqVO.getName());
        if (!customerDO.getName().equals(updateReqVO.getName())
                && CollUtil.isNotEmpty(repeatOwnerUserNameList)
                && updateReqVO.getRepeatConfirmationFlag() == 0) {
            List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
            throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?"));
        }

        // 更新
        CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);
        // 由于这里是 size 而排序是从0开始的 所以这里递增一个直接用size即可
        updateObj.setSortNum(repeatOwnerUserNameList.size());
        customerMapper.updateById(updateObj);

        //插入日志
        crmOperatelogService.createLog("修改客户", updateReqVO.getId(), 0L, 0L);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCustomerPurchaseTotal(CrmCustomerSaveReqVO updateReqVO) {

        // 校验存在
        CrmCustomerDO customerDO = validateCustomerExists(updateReqVO.getId());

        // 更新
        updateReqVO.setPurchaseTimes(customerDO.getPurchaseTimes() + 1);
        updateReqVO.setPurchaseTotal(customerDO.getPurchaseTotal().add(updateReqVO.getPurchaseTotal()));
        CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);

        customerMapper.updateById(updateObj);

        //插入日志
        crmOperatelogService.createLog("修改客户", updateReqVO.getId(), 0L, 0L);

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCustomer(Long id) {
        // 校验存在
        validateCustomerExists(id);
        //判断客户关联
        Long count = crmBusinessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>().eq(CrmBusinessDO::getCustomerId, id));
        if (count > 0) {
            throw exception(new ErrorCode(20241010, "当前客户下有商机不可以删除"));
        }
        Long count2 = contractMapper.selectCount(new LambdaQueryWrapper<CrmContractDO>().eq(CrmContractDO::getCustomerId, id));
        if (count2 > 0) {
            throw exception(new ErrorCode(20241010, "当前客户下有合同不可以删除"));
        }
        Long count3 = contractReceivablesMapper.selectCount(new LambdaQueryWrapper<CrmContractReceivablesDO>().eq(CrmContractReceivablesDO::getCustomerId, id));
        if (count3 > 0) {
            throw exception(new ErrorCode(20241010, "当前客户下有商机不可以删除"));
        }

        // 删除
        customerMapper.deleteById(id);

        //删除记录
        crmRecordMapper.delete(new LambdaQueryWrapper<CrmRecordDO>()
                .eq(CrmRecordDO::getTypes, TypesEnum.CUSTOMER.getValue())
                .eq(CrmRecordDO::getTypesId, id));
        customerContactsMapper.delete(new LambdaQueryWrapper<CrmCustomerContactsDO>().eq(CrmCustomerContactsDO::getCustomerId, id));


        //插入日志
        crmOperatelogService.createLog("删除客户", id, 0L, 0L);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void openCustomer(Long id) {
        CrmCustomerDO customerDO = customerMapper.selectById(id);
        if (customerDO == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
        //设置拥有0
        customerDO.setOwnerUserId(0L);
        customerMapper.updateById(customerDO);
        //设置联系人的拥有0
        customerContactsMapper.update(CrmCustomerContactsDO.builder().ownerUserId(0L).build(),
                new LambdaQueryWrapper<CrmCustomerContactsDO>().eq(CrmCustomerContactsDO::getCustomerId, id));

        //插入日志
        crmOperatelogService.createLog("放入公海", id, 0L, 0L);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiveCustomer(Long id) {
        CrmCustomerDO customerDO = customerMapper.selectById(id);
        if (customerDO == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
        customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        customerDO.setCollectTime(LocalDateTime.now());
        customerDO.setFollowTime(LocalDateTime.now());
        customerMapper.updateById(customerDO);

        //更新联系人
        customerContactsMapper.update(CrmCustomerContactsDO.builder()
                        .ownerUserId(SecurityFrameworkUtils.getLoginUserId()).build(),
                new LambdaQueryWrapper<CrmCustomerContactsDO>().eq(CrmCustomerContactsDO::getCustomerId, id));

        //插入日志
        crmOperatelogService.createLog("公海领取客户", id, 0L, 0L);
    }

    private CrmCustomerDO validateCustomerExists(Long id) {
        CrmCustomerDO customerDO = customerMapper.selectById(id);
        if (customerDO == null) {
            throw exception(CUSTOMER_NOT_EXISTS);
        }
        return customerDO;
    }

    @Override
    public CrmCustomerDO getCustomer(Long id) {
        return customerMapper.selectById(id);
    }

    @Override
    public PageResult<CrmCustomerDO> getCustomerPage(CrmCustomerPageReqVO pageReqVO) {
        List<Long> ids = new ArrayList<>();
        Long adminId = SecurityFrameworkUtils.getLoginUserId();
        if (CustomerTypesEnum.OPEN.getValue().equals(pageReqVO.getType())) {
            ids.add(0L);
        } else {
            if (RelationEnum.MY.getValue().equals(pageReqVO.getRelation())) {
                ids.add(adminId);
            } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
                ids = userLiveTreeService.getItemIdsByUserId(adminId);
            }
        }
        if (CollUtil.isEmpty(ids)) {
            return PageResult.empty();
        }
        IPage<CrmCustomerDO> pageResult;
        IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
        if (pageReqVO.getDistinctFlag() == 0) {
            pageResult = customerMapper.selectPage(mpPage, pageReqVO, ids);
        } else {
            pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids);
        }
        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
    }


    @Override
    public PageResult<CrmCustomerRespVO> getCustomerPage2(CrmCustomerPageReqVO pageReqVO) {
        List<Long> ids = new ArrayList<>();
        Long adminId = SecurityFrameworkUtils.getLoginUserId();
        if (CustomerTypesEnum.OPEN.getValue().equals(pageReqVO.getType())) {
            ids.add(0L);
        } else {
            if (RelationEnum.MY.getValue().equals(pageReqVO.getRelation())) {
                ids.add(adminId);
            } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
                ids = userLiveTreeService.getItemIdsByUserId(adminId);
            }
        }
        if (CollUtil.isEmpty(ids)) {
            return PageResult.empty();
        }
        IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList2(mpPage, pageReqVO, ids);
        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
    }

    @Override
    public CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String adminIds,
                                           Integer averageType, Integer repeatConfirmationFlag) {
        CustomerImportRespVO respVO = CustomerImportRespVO.builder().createNames(new ArrayList<>())
                .failureNames(new LinkedHashMap<>()).build();
        //处理客户归属方案
        //如果只选择了机构没有选择用户直接获取当前部门下的用户
        List<Long> userList = new ArrayList<>();
        if (StrUtil.isNotEmpty(adminIds)) {
            userList = StrUtil.split(adminIds, ",").stream().map(Long::parseLong).collect(Collectors.toList());
        }
        int i = 1;
        int j = 0;
        int adminCount = userList.size();
        List<CrmCustomerDO> customerList = new ArrayList<>();
        // -- 查询重复
        Map<String, Integer> map = new HashMap<>();
        if (repeatConfirmationFlag == 0) {
            List<String> nameList = importUsers.stream().map(CrmCustomerImportVO::getName).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
            if (CollUtil.isNotEmpty(nameList)) {
                List<CrmCustomerDO> crmCustomerDOS = customerMapper.selectList(new LambdaQueryWrapper<CrmCustomerDO>()
                        .in(CrmCustomerDO::getName, nameList));
                map = crmCustomerDOS.stream().collect(Collectors.groupingBy(CrmCustomerDO::getName, Collectors.summingInt(e -> 1)));
            }
        }
        for (CrmCustomerImportVO importVO : importUsers) {
            if (StrUtil.isEmpty(importVO.getName())) {
                respVO.getFailureNames().put("第" + i + "行:", "客户名称为空，已经被过滤掉");
                continue;
            }
            if (repeatConfirmationFlag == 0) {
                Integer num = map.get(importVO.getName());
                if (num != null && num > 1) {
                    respVO.getFailureNames().put("第" + i + "行:", "客户名称重复，已经被过滤掉");
                    continue;
                }
            }
            CrmCustomerDO customer = BeanUtils.toBean(importVO, CrmCustomerDO.class);
            Long adminId = 0L;
            if (ShopCommonEnum.AVG_1.getValue().equals(averageType)) {
                //平均分配
                adminId = userList.get(j);
                if (j == (adminCount - 1)) {
                    j = 0;
                } else {
                    j++;
                }
            } else {
                //随机分配
                Random random = new Random();
                int num = random.nextInt(adminCount);
                adminId = userList.get(num);
            }
            Integer num = map.get(importVO.getName());
            if (num != null && num > 1) {
                map.put(importVO.getName(), num + 1);
            } else if (num == null) {
                num = 0;
                map.put(importVO.getName(), num);
            }
            customer.setSortNum(num);
            customer.setOwnerUserId(adminId);
            customerList.add(customer);
            respVO.getCreateNames().add("第" + i + "行:导入成功用户名->" + importVO.getName());
            i++;
        }
        if (!customerList.isEmpty()) {
            customerMapper.insertBatch(customerList);
        }
        return respVO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recover(CrmCustomerRecoverVO recoverVO) {
        //离职人员客户
        List<CrmCustomerDO> crmCustomerDOS = customerMapper.selectList(new LambdaQueryWrapper<CrmCustomerDO>().
                in(CrmCustomerDO::getOwnerUserId, recoverVO.getLeaveAdminIds()));
        if (crmCustomerDOS == null || crmCustomerDOS.isEmpty()) {
            throw exception(new ErrorCode(202409090, "离职员工下没有客户哦"));
        }

        int adminCount = recoverVO.getOwnerAdminIds().size();
        int i = 0;
        for (CrmCustomerDO customerDO : crmCustomerDOS) {
            Long adminId = 0L;
            if (ShopCommonEnum.AVG_1.getValue().equals(recoverVO.getAverageType())) {
                //平均分配
                adminId = recoverVO.getOwnerAdminIds().get(i);
                if (i == (adminCount - 1)) {
                    i = 0;
                } else {
                    i++;
                }
            } else {
                //随机分配
                Random random = new Random();
                int num = random.nextInt(adminCount);
                adminId = recoverVO.getOwnerAdminIds().get(num);
            }
            customerDO.setOwnerUserId(adminId);
            customerDO.setCollectTime(LocalDateTime.now());

            customerMapper.updateById(customerDO);
            //处理日志
            crmOperatelogService.createLog("客户资料回收", customerDO.getId(), 0L, 0L);
            //联系人也转移
            customerContactsMapper.update(CrmCustomerContactsDO.builder().ownerUserId(adminId).build(),
                    new LambdaQueryWrapper<CrmCustomerContactsDO>()
                            .eq(CrmCustomerContactsDO::getCustomerId, customerDO.getId()));
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(CrmCustomerTransferVO transferVO) {
        //客户
        List<CrmCustomerDO> crmCustomerDOS = customerMapper.selectList(new LambdaQueryWrapper<CrmCustomerDO>().
                in(CrmCustomerDO::getId, transferVO.getCustomerIds()));
        if (crmCustomerDOS == null || crmCustomerDOS.isEmpty()) {
            throw exception(new ErrorCode(202409091, "客户信息不存在"));
        }

        int adminCount = transferVO.getOwnerAdminIds().size();
        int i = 0;
        for (CrmCustomerDO customerDO : crmCustomerDOS) {
            Long adminId;
            if (ShopCommonEnum.AVG_1.getValue().equals(transferVO.getAverageType())) {
                //平均分配
                adminId = transferVO.getOwnerAdminIds().get(i);
                if (i == (adminCount - 1)) {
                    i = 0;
                } else {
                    i++;
                }
            } else {
                //随机分配
                Random random = new Random();
                int num = random.nextInt(adminCount);
                adminId = transferVO.getOwnerAdminIds().get(num);
            }
            customerDO.setOwnerUserId(adminId);
            customerDO.setCollectTime(LocalDateTime.now());

            customerMapper.updateById(customerDO);
            //处理日志
            crmOperatelogService.createLog("转移客户", customerDO.getId(), 0L, 0L);
            //联系人也转移
            customerContactsMapper.update(CrmCustomerContactsDO.builder().ownerUserId(adminId).build(),
                    new LambdaQueryWrapper<CrmCustomerContactsDO>()
                            .eq(CrmCustomerContactsDO::getCustomerId, customerDO.getId()));
        }
    }

    @Override
    public void sendSms(SmsTemplateSendVO sendVO) {
        List<CrmCustomerContactsDO> crmCustomerDOS = null;
        if (sendVO.getIsCustomer()) {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getCustomerId, sendVO.getCustomerIds()));
        } else {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getId, sendVO.getCustomerIds()));
        }

        if (crmCustomerDOS == null || crmCustomerDOS.isEmpty()) {
            throw exception(new ErrorCode(202409100, "客户信息不存在"));
        }
        crmCustomerDOS.forEach(customer -> {
            //发送短信
            if (StrUtil.isNotEmpty(customer.getMobile())) {
                smsSendApi.sendSingleSms(new SmsSendSingleReqDTO().setMobile(customer.getMobile())
                        .setUserId(customer.getId()).setUserType(UserTypeEnum.CUSTOMER.getValue())
                        .setTemplateCode(sendVO.getTemplateCode()).setTemplateParams(sendVO.getTemplateParams()));
            }
        });

    }

    @Override
    public void sendMail(MailTemplateSendVO sendVO) {
        List<CrmCustomerContactsDO> crmCustomerDOS = null;
        if (sendVO.getIsCustomer()) {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getCustomerId, sendVO.getCustomerIds()));
        } else {
            crmCustomerDOS = customerContactsMapper.selectList(new LambdaQueryWrapper<CrmCustomerContactsDO>().
                    in(CrmCustomerContactsDO::getId, sendVO.getCustomerIds()));
        }
        if (crmCustomerDOS == null || crmCustomerDOS.isEmpty()) {
            throw exception(new ErrorCode(202409101, "客户信息不存在"));
        }
        crmCustomerDOS.forEach(customer -> {
            //发送邮件
            if (StrUtil.isNotEmpty(customer.getEmail())) {
                mailSendApi.sendSingleMail(new MailSendSingleReqDTO()
                        .setMail(customer.getEmail()).setUserId(customer.getId()).setUserType(UserTypeEnum.CUSTOMER.getValue())
                        .setTemplateCode(sendVO.getTemplateCode()).setTemplateParams(sendVO.getTemplateParams()));
            }
        });
    }
}
