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

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.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.crmclues.vo.*;
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerImportRespVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.CluesStatusEnum;
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.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
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.CLUES_NOT_EXISTS;

/**
 * 线索 Service 实现类
 *
 * @author yshop
 */
@Service
@Validated
public class CrmCluesServiceImpl implements CrmCluesService {

    @Resource
    private CrmCluesMapper cluesMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private CrmCustomerMapper customerMapper;
    @Resource
    private CrmRecordMapper crmRecordMapper;
    @Resource
    private UserLiveTreeService userLiveTreeService;

    @Override
    public Long createClues(CrmCluesSaveReqVO createReqVO) {
        // 插入
        CrmCluesDO clues = BeanUtils.toBean(createReqVO, CrmCluesDO.class);
        clues.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        cluesMapper.insert(clues);
        // 返回
        return clues.getId();
    }

    @Override
    public void updateClues(CrmCluesSaveReqVO updateReqVO) {
        // 校验存在
        validateCluesExists(updateReqVO.getId());
        // 更新
        CrmCluesDO updateObj = BeanUtils.toBean(updateReqVO, CrmCluesDO.class);
        cluesMapper.updateById(updateObj);
    }

    @Override
    public void deleteClues(Long id) {
        // 校验存在
        validateCluesExists(id);
        // 删除
        cluesMapper.deleteById(id);

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

    private void validateCluesExists(Long id) {
        if (cluesMapper.selectById(id) == null) {
            throw exception(CLUES_NOT_EXISTS);
        }
    }

    @Override
    public CrmCluesDO getClues(Long id) {
        return cluesMapper.selectById(id);
    }

    @Override
    public PageResult<CrmCluesRespVO> getCluesPage(CrmCluesPageReqVO pageReqVO) {
        if (CustomerTypesEnum.OPEN.getValue().equals(pageReqVO.getType())) {
            IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
            IPage<CrmCluesRespVO> page = cluesMapper.selectPageList2(mpPage, pageReqVO);
            return new PageResult<>(page.getRecords(), page.getTotal());
        }
        List<Long> ids = new ArrayList<>();
        Long adminId = SecurityFrameworkUtils.getLoginUserId();
        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<CrmCluesRespVO> page = cluesMapper.selectPageList(mpPage, pageReqVO, ids);
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public void openClues(Long id) {
        CrmCluesDO crmCluesDO = cluesMapper.selectById(id);
        if (CluesStatusEnum.STATUS_0.getValue().equals(crmCluesDO.getStatus())) {
            crmCluesDO.setStatus(CluesStatusEnum.STATUS_NEG_1.getValue());
        }
        crmCluesDO.setOwnerUserId(0L);
        cluesMapper.updateById(crmCluesDO);
    }

    @Override
    public void receiveClues(Long id) {
        CrmCluesDO crmCluesDO = cluesMapper.selectById(id);
        if (crmCluesDO == null) {
            throw exception(CLUES_NOT_EXISTS);
        }
        crmCluesDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        crmCluesDO.setCollectTime(LocalDateTime.now());
        crmCluesDO.setFollowTime(LocalDateTime.now());
        cluesMapper.updateById(crmCluesDO);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createCustomer(CrmCustomerSaveReqVO createReqVO) {
        CrmCluesDO crmCluesDO = cluesMapper.selectById(createReqVO.getId());
        if (crmCluesDO == null) {
            throw exception(CLUES_NOT_EXISTS);
        }
        if (CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())) {
            throw exception(new ErrorCode(202411160, "已经转化成客户！"));
        }
        // 判断客户名称是否唯一
        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) + "添加过,是否继续添加?"));        }
        createReqVO.setId(null);
        CrmCustomerDO customerDO = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
        customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
        customerDO.setNextTime(LocalDateTime.now());
        customerDO.setCollectTime(LocalDateTime.now());
        customerMapper.insert(customerDO);
        //更新线索
        crmCluesDO.setStatus(CluesStatusEnum.STATUS_1.getValue());
        crmCluesDO.setCustomerId(customerDO.getId());
        cluesMapper.updateById(crmCluesDO);

        //是否更新跟踪记录
        if (ShopCommonEnum.ENABLE_1.getValue().equals(createReqVO.getIsTransfer())) {
            crmRecordMapper.update(CrmRecordDO.builder()
                            .types(TypesEnum.CUSTOMER.getValue())
                            .typesId(customerDO.getId()).build(),
                    new LambdaQueryWrapper<CrmRecordDO>().eq(CrmRecordDO::getTypesId, crmCluesDO.getId()));
        }
    }


    @Override
    public CustomerImportRespVO importList(List<CrmCluesImportVO> importUsers, String deptId, String adminIds,
                                           Integer averageType) {
        CustomerImportRespVO respVO = CustomerImportRespVO.builder().createNames(new ArrayList<>())
                .failureNames(new LinkedHashMap<>()).build();
        //处理客户归属方案
        //如果只选择了机构没有选择用户直接获取当前部门下的用户
        List<Long> userList = null;
        if (StrUtil.isNotEmpty(deptId) && StrUtil.isEmpty(adminIds)) {
            List<AdminUserApiVO> adminUserDOS = adminUserApi.getUserList(new AdminUserApiDTO().setDeptId(Long.valueOf(deptId)).setNextDept(1)).getCheckedData();
            userList = adminUserDOS.stream().map(AdminUserApiVO::getId).collect(Collectors.toList());
            if (userList.isEmpty()) {
                throw exception(new ErrorCode(202409110, "当前部门下没有用户，清重新选择"));
            }
        } else {
            userList = StrUtil.split(adminIds, ",").stream().map(Long::parseLong).collect(Collectors.toList());
        }


        int i = 1;
        int j = 0;
        int adminCount = userList.size();
        for (CrmCluesImportVO importVO : importUsers) {
            if (StrUtil.isEmpty(importVO.getName())) {
                respVO.getFailureNames().put("第" + i + "行:", "线索名称为空，已经被过滤掉");
                continue;
            }
            Long count = cluesMapper.selectCount(new LambdaQueryWrapper<CrmCluesDO>()
                    .eq(CrmCluesDO::getName, importVO.getName()));
            if (count > 0) {
                respVO.getFailureNames().put("第" + i + "行:", "线索名称已经存在，已经被过滤掉");
                continue;
            }
            CrmCluesDO crmCluesDO = BeanUtils.toBean(importVO, CrmCluesDO.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);
            }
            crmCluesDO.setOwnerUserId(adminId);
            cluesMapper.insert(crmCluesDO);
            respVO.getCreateNames().add("第" + i + "行:导入成功用户名->" + importVO.getName());
            i++;
        }
        return respVO;
    }


    @Override
    public void transfer(CrmCluesTransferVO transferVO) {
        //客户
        List<CrmCluesDO> crmCluesDOS = cluesMapper.selectList(new LambdaQueryWrapper<CrmCluesDO>().
                in(CrmCluesDO::getId, transferVO.getCluesIds()));
        if (crmCluesDOS == null || crmCluesDOS.isEmpty()) {
            throw exception(new ErrorCode(202409111, "线索信息不存在"));
        }

        int adminCount = transferVO.getOwnerAdminIds().size();
        int i = 0;
        for (CrmCluesDO crmCluesDO : crmCluesDOS) {
            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);
            }
            crmCluesDO.setOwnerUserId(adminId);
            crmCluesDO.setCollectTime(LocalDateTime.now());

            cluesMapper.updateById(crmCluesDO);
        }
    }

    @Override
    public List<CrmCluesStatisticsRespVO> getCluesStatisticsByUserIds(List<Long> ownerUserIds, LocalDateTime[] createTime) {

        return cluesMapper.selectStatisticsByUserIds(ownerUserIds, createTime);
    }

    @Override
    public void autoConfirmJob() {
        // 获取负责人不为0 并且跟进记录为3天以外的数据
        List<CrmCluesDO> crmCluesDOS = cluesMapper.selectList(new LambdaQueryWrapper<CrmCluesDO>()
                .ne(CrmCluesDO::getOwnerUserId, 0)
                .in(CrmCluesDO::getStatus, Arrays.asList(CluesStatusEnum.STATUS_0.getValue(), CluesStatusEnum.STATUS_NEG_1.getValue()))
                .le(CrmCluesDO::getFollowTime, LocalDateTime.now().minusDays(3)));
        for (CrmCluesDO crmCluesDO : crmCluesDOS) {
            crmCluesDO.setOwnerUserId(0L);
        }
        if (CollUtil.isNotEmpty(crmCluesDOS)) {
            cluesMapper.updateBatch(crmCluesDOS);
        }
    }

}
