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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO;
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.crmcustomer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecorduser.CrmRecordUserDO;
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.crmcustomer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecorduser.CrmRecordUserMapper;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
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 com.github.yulichang.wrapper.MPJLambdaWrapper;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.RECORD_NOT_EXISTS;

/**
 * 跟进记录 Service 实现类
 *
 * @author yshop
 */
@Service
@Validated
public class CrmRecordServiceImpl implements CrmRecordService {

    @Resource
    private CrmRecordMapper recordMapper;
    @Resource
    private CrmRecordUserMapper crmRecordUserMapper;
    @Resource
    private CrmCustomerMapper customerMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private CrmBusinessMapper crmBusinessMapper;
    @Resource
    private CrmCluesMapper cluesMapper;
    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private UserLiveTreeService userLiveTreeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createRecord(CrmRecordSaveReqVO createReqVO) {
        // 插入
        CrmRecordDO record = BeanUtils.toBean(createReqVO, CrmRecordDO.class);
        recordMapper.insert(record);
        // -- 插入跟进用户
        List<CrmRecordUserDO> recordUsers = new ArrayList<>();
        for (Long userId : createReqVO.getUserIds()) {
            recordUsers.add(new CrmRecordUserDO().setRecordId(record.getId()).setUserId(userId));
        }
        if (!recordUsers.isEmpty()) {
            crmRecordUserMapper.insertBatch(recordUsers);
        }
        //更新客户
        if (TypesEnum.CUSTOMER.getValue().equals(createReqVO.getTypes())) {
            customerMapper.updateById(CrmCustomerDO.builder()
                    .id(createReqVO.getTypesId())
                    .nextTime(createReqVO.getNextTime())
                    .followStatus(createReqVO.getFollowStatus())
                    .followTime(LocalDateTime.now())
                    .build());
        } else if (TypesEnum.BUSINESS.getValue().equals(createReqVO.getTypes())) {
            //更新商机
            CrmBusinessDO crmBusinessDO = crmBusinessMapper.selectById(createReqVO.getTypesId());
            crmBusinessDO.setNextTime(createReqVO.getNextTime());
            crmBusinessMapper.updateById(crmBusinessDO);
            customerMapper.updateById(CrmCustomerDO.builder()
                    .id(crmBusinessDO.getCustomerId())
                    .nextTime(createReqVO.getNextTime())
                    .followTime(LocalDateTime.now())
                    .build());
        } else if (TypesEnum.CLUES.getValue().equals(createReqVO.getTypes())) {
            //更新线索
            cluesMapper.updateById(CrmCluesDO.builder()
                    .id(createReqVO.getTypesId())
                    .followStatus(createReqVO.getFollowStatus())
                    .nextTime(createReqVO.getNextTime())
                    .followTime(LocalDateTime.now())
                    .build());
        }
        // 返回
        return record.getId();
    }

    @Override
    public void updateRecord(CrmRecordSaveReqVO updateReqVO) {
        // 校验存在
        validateRecordExists(updateReqVO.getId());
        // 更新
        CrmRecordDO updateObj = BeanUtils.toBean(updateReqVO, CrmRecordDO.class);
        recordMapper.updateById(updateObj);
        // -- 编辑更近用户的话
        List<CrmRecordUserDO> oldCrmRecordUsers = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>()
                .eq(CrmRecordUserDO::getRecordId, updateReqVO.getId()));
        List<Long> oldUserIds = oldCrmRecordUsers.stream().map(CrmRecordUserDO::getUserId).collect(Collectors.toList());
        List<Long> userIds = updateReqVO.getUserIds();
        List<List<Long>> list = CollectionUtils.diffList(oldUserIds, userIds,
                ObjectUtil::equal
        );
        if (CollUtil.isNotEmpty(list.get(0))) {
            List<CrmRecordUserDO> crmRecordUserDOS = new ArrayList<>();
            for (Long userId : list.get(0)) {
                CrmRecordUserDO crmRecordUserDO = new CrmRecordUserDO();
                crmRecordUserDO.setRecordId(updateReqVO.getId());
                crmRecordUserDO.setUserId(userId);
                crmRecordUserDOS.add(crmRecordUserDO);
            }
            crmRecordUserMapper.insertBatch(crmRecordUserDOS);
        }
        if (CollUtil.isNotEmpty(list.get(2))) {
            crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>()
                    .in(CrmRecordUserDO::getUserId, list.get(2)));
        }
    }

    @Override
    public void deleteRecord(Long id) {
        // 校验存在
        validateRecordExists(id);
        // 删除该记录下的跟进用户
        Long adminId = SecurityFrameworkUtils.getLoginUserId();
        List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id));
        crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id).eq(CrmRecordUserDO::getUserId, adminId));
        // 删除如果是最后一个的话删除一下
        if (crmRecordUserDOS.size() == 1 && adminId.equals(crmRecordUserDOS.get(0).getUserId())) {
            recordMapper.deleteById(id);
        }
    }

    private void validateRecordExists(Long id) {
        if (recordMapper.selectById(id) == null) {
            throw exception(RECORD_NOT_EXISTS);
        }
    }

    @Override
    public CrmRecordDO getRecord(Long id) {
        return recordMapper.selectById(id);
    }

    @Override
    public PageResult<CrmRecordRespVO> getRecordPage(CrmRecordPageReqVO pageReqVO) {
        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);
        }
        LocalDateTime beginTime = pageReqVO.getNextTime() != null && pageReqVO.getNextTime().length > 0 ? pageReqVO.getNextTime()[0] : null;
        LocalDateTime endTime = pageReqVO.getNextTime() != null && pageReqVO.getNextTime().length > 0 ? pageReqVO.getNextTime()[1] : null;
        MPJLambdaWrapper<CrmRecordDO> wrapper = new MPJLambdaWrapper<CrmRecordDO>()
                .selectAll(CrmRecordDO.class)
                .leftJoin(CrmRecordUserDO.class, CrmRecordUserDO::getRecordId, CrmRecordDO::getId)
                .eqIfExists(CrmRecordDO::getTypes, pageReqVO.getTypes())
                .eqIfExists(CrmRecordDO::getTypesId, pageReqVO.getTypesId())
                .eqIfExists(CrmRecordDO::getContent, pageReqVO.getContent())
                .eqIfExists(CrmRecordDO::getRecordType, pageReqVO.getRecordType())
                .ge(beginTime != null, CrmRecordDO::getNextTime, beginTime)
                .le(endTime != null, CrmRecordDO::getNextTime, endTime)
                .in(CollUtil.isNotEmpty(ids), CrmRecordUserDO::getUserId, ids)
                .groupBy(CrmRecordDO::getId)
                .orderByDesc(CrmRecordDO::getId);
        PageResult<CrmRecordDO> pageResult = recordMapper.selectJoinPage(pageReqVO, CrmRecordDO.class, wrapper);
        PageResult<CrmRecordRespVO> pageResult1 = BeanUtils.toBean(pageResult, CrmRecordRespVO.class);
        List<CrmRecordRespVO> list = pageResult1.getList();
        Map<Long, List<CrmRecordUserDO>> crmRecordUserMap = new HashMap<>();
        List<CrmRecordUserDO> crmRecordUserList = new ArrayList<>();
        if (CollUtil.isNotEmpty(list)) {
            crmRecordUserList = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().in(CrmRecordUserDO::getRecordId, list.stream().map(CrmRecordRespVO::getId).collect(Collectors.toList())));
            crmRecordUserMap = crmRecordUserList.stream().collect(Collectors.groupingBy(CrmRecordUserDO::getRecordId));
        }

        List<String> recordTypes = list.stream().map(CrmRecordRespVO::getRecordType).map(String::valueOf).collect(Collectors.toList());
        List<DictDataRespDTO> respDTOS = CollUtil.isNotEmpty(recordTypes) ? dictDataApi.getByValues(new DictParameterRespDTO().setDictType("follow_status").setValues(recordTypes)).getCheckedData() : new ArrayList<>();
        Map<String, DictDataRespDTO> dictDataMap = CollectionUtils.convertMap(respDTOS, DictDataRespDTO::getValue);
        Map<String, List<Long>> typeIdMap = list.stream().collect(Collectors.groupingBy(CrmRecordRespVO::getTypes, Collectors.mapping(CrmRecordRespVO::getTypesId, Collectors.toList())));
        // 批量查询客户、业务和线索数据
        Map<Long, CrmCustomerDO> customerMap = new HashMap<>();
        if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.CUSTOMER.getValue()))) {
            customerMap = customerMapper.selectBatchIds(typeIdMap.get(TypesEnum.CUSTOMER.getValue())).stream()
                    .collect(Collectors.toMap(CrmCustomerDO::getId, item -> item));
        }
        Map<Long, CrmBusinessDO> businessMap = new HashMap<>();
        if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.BUSINESS.getValue()))) {
            businessMap = crmBusinessMapper.selectBatchIds(typeIdMap.get(TypesEnum.BUSINESS.getValue())).stream()
                    .collect(Collectors.toMap(CrmBusinessDO::getId, item -> item));
        }
        Map<Long, CrmCluesDO> cluesMap = new HashMap<>();
        if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.CLUES.getValue()))) {
            cluesMap = cluesMapper.selectBatchIds(typeIdMap.get(TypesEnum.CLUES.getValue())).stream()
                    .collect(Collectors.toMap(CrmCluesDO::getId, item -> item));
        }
        List<Long> userIds = crmRecordUserList.stream().map(CrmRecordUserDO::getUserId).distinct().collect(Collectors.toList());
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserList(userIds).getCheckedData().stream().collect(Collectors.toMap(AdminUserRespDTO::getId, item -> item));
        for (CrmRecordRespVO crmRecordRespVO : list) {
            // 设置记录类型名称
            DictDataRespDTO dto = dictDataMap.get(crmRecordRespVO.getRecordType().toString());
            if (dto != null) {
                crmRecordRespVO.setRecordTypeName(dto.getLabel());
            }
            // 根据类型设置名称
            String types = crmRecordRespVO.getTypes();
            if (TypesEnum.CUSTOMER.getValue().equals(types)) {
                CrmCustomerDO customerDO = customerMap.get(crmRecordRespVO.getTypesId());
                if (customerDO != null) {
                    crmRecordRespVO.setTypesName(customerDO.getName());
                }
            } else if (TypesEnum.BUSINESS.getValue().equals(types)) {
                CrmBusinessDO crmBusinessDO = businessMap.get(crmRecordRespVO.getTypesId());
                if (crmBusinessDO != null) {
                    crmRecordRespVO.setTypesName(crmBusinessDO.getName());
                }
            } else if (TypesEnum.CLUES.getValue().equals(types)) {
                CrmCluesDO crmCluesDO = cluesMap.get(crmRecordRespVO.getTypesId());
                if (crmCluesDO != null) {
                    crmRecordRespVO.setTypesName(crmCluesDO.getName());
                }
            }
            // 获取创建者信息
            List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMap.get(crmRecordRespVO.getId());
            List<AdminUserRespDTO> adminUserRespDTOS = new ArrayList<>();
            if (CollUtil.isEmpty(crmRecordUserDOS)) {
                crmRecordRespVO.setAdminUserRespDTOS(adminUserRespDTOS);
                continue;
            }
            for (CrmRecordUserDO crmRecordUserDO : crmRecordUserDOS) {
                AdminUserRespDTO adminUserRespDTO = userMap.get(crmRecordUserDO.getUserId());
                adminUserRespDTOS.add(adminUserRespDTO);
            }
            crmRecordRespVO.setAdminUserRespDTOS(adminUserRespDTOS);
        }
        return pageResult1;
    }

    @Override
    public List<RecordStatisticsRespVO> getRecordStatistics(List<Long> userIds, LocalDateTime[] createTime) {

        return recordMapper.selectStatistics(userIds, createTime);
    }

}
