package com.cool.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.dao.*;
import com.cool.store.dto.point.AuditNodeDTO;
import com.cool.store.dto.point.MiniPointPageDTO;
import com.cool.store.entity.*;
import com.cool.store.enums.*;
import com.cool.store.enums.point.*;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.*;
import com.cool.store.service.*;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.utils.poi.DateUtils;
import com.cool.store.utils.poi.StringUtils;
import com.cool.store.vo.AuditInfoVO;
import com.cool.store.vo.LinePointBaseInfoVO;
import com.cool.store.vo.point.*;
import com.cool.store.vo.shop.RentInfoToDoVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhangchenbiao
 * @FileName: ShopPointServiceImpl
 * @Description:
 * @date 2024-03-29 15:25
 */
@Slf4j
@Service
public class PointServiceImpl implements PointService {

    @Resource
    private ShopInfoDAO shopInfoDAO;
    @Resource
    private PointInfoDAO pointInfoDAO;
    @Resource
    private PointDetailInfoDAO pointDetailInfoDAO;
    @Resource
    private LineInfoDAO lineInfoDAO;
    @Resource
    private PointRecommendDAO pointRecommendDAO;
    @Resource
    private RedisUtilPool redisUtilPool;
    @Resource
    private UserAuthMappingService userAuthMappingService;
    @Resource
    private PointAuditRecordDAO pointAuditRecordDAO;
    @Resource
    private PointTodoInfoDAO pointTodoInfoDAO;
    @Resource
    private EnterpriseUserDAO enterpriseUserDAO;
    @Resource
    private RegionService regionService;
    @Resource
    private LabelService labelService;
    @Resource
    private HyOpenAreaInfoDAO hyOpenAreaInfoDAO;
    @Resource
    private ShopStageInfoDAO shopStageInfoDAO;
    @Resource
    private ShopRentInfoDAO shopRentInfoDAO;
    @Resource
    private ShopAuditInfoDAO shopAuditInfoDAO;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    private CommonService commonService;
    @Value("${mybatis.configuration.variables.enterpriseId}")
    private String enterpriseId;

    private static final String AUDIT_SETTING_KEY = "audit_setting_key:{0}";
    private static final String POINT_SELECT_KEY = "point_select_key:{0}:{1}";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addPointDetailInfo(AddPointDetailRequest shopPointDetailRequest, String userId) {
        PointInfoDO pointInfo = AddPointDetailRequest.convertPointDO(shopPointDetailRequest);
        pointInfo.setPointCode(generateCode());
        pointInfo.setDevelopmentManager(userId);
        pointInfo.setDevelopmentTime(new Date());
        Long pointId = pointInfoDAO.addPointInfo(pointInfo);
        PointDetailInfoDO shopPoint = AddPointDetailRequest.convertDO(shopPointDetailRequest);
        shopPoint.setPointId(pointId);
        return pointDetailInfoDAO.addPointDetailInfo(shopPoint);
    }

    @Override
    public PointDetailVO getPointDetailInfo(Long pointId, Boolean isGetNodeNo) {
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        if(Objects.isNull(pointInfo)){
            log.error("铺位基本信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        PointDetailInfoDO pointDetailInfo = pointDetailInfoDAO.getPointDetailInfoByPointId(pointId);
        if(Objects.isNull(pointDetailInfo)){
            log.error("铺位详情信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        String userName = enterpriseUserDAO.getUserName(pointInfo.getDevelopmentManager());
        PointDetailVO result = PointDetailVO.convertVO(pointInfo, pointDetailInfo);
        result.setDevelopmentManagerUserName(userName);
        result.setDevelopmentManagerUserId(pointInfo.getDevelopmentManager());
        result.setRegionNodeName(regionService.getBelongWarRegionName(pointInfo.getRegionId()));
        if(Objects.nonNull(isGetNodeNo) && isGetNodeNo){
            result.setCurNodeNo(pointTodoInfoDAO.getCurNodeNoByPoint(pointId));
        }
        if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus())){
            List<Long> canSubmitRentContractShopIds = shopStageInfoDAO.getCanSubmitRentContractShopIds(Arrays.asList(pointInfo.getShopId()));
            boolean canSubmitRentContract = CollectionUtils.isEmpty(canSubmitRentContractShopIds) ? Boolean.FALSE : Boolean.TRUE;
            result.setCanSubmitRentContract(canSubmitRentContract);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long updatePointDetailInfo(UpdatePointDetailRequest shopPointDetailRequest) {
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(shopPointDetailRequest.getPointId());
        if(Objects.isNull(pointInfo)){
            log.error("铺位基本信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        PointInfoDO shopPointInfo = UpdatePointDetailRequest.convertPointDO(shopPointDetailRequest);
        PointDetailInfoDO shopPoint = UpdatePointDetailRequest.convertDO(shopPointDetailRequest);
        shopPointInfo.setPointScore(shopPoint.getTotalPointScore());
        pointInfoDAO.perfectPointInfo(shopPointInfo);
        pointDetailInfoDAO.updatePartFieldPointDetail(shopPoint);
        return shopPointDetailRequest.getPointId();
    }

    @Override
    public Integer generateEvaluationReport(Long pointId) {
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        PointDetailInfoDO pointDetailInfo = pointDetailInfoDAO.getPointDetailInfoByPointId(pointId);
        if(Objects.isNull(pointInfo) || Objects.isNull(pointDetailInfo)){
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        if(!pointDetailInfo.isCanSubmitEvaluable() || StringUtils.isBlank(pointInfo.getPointArea())){
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_COMPLETE);
        }
        Integer totalPointScore = pointDetailInfo.getTotalPointScore();
        PointInfoDO updatePointInfo = new PointInfoDO();
        updatePointInfo.setId(pointId);
        updatePointInfo.setPointScore(totalPointScore);
        updatePointInfo.setPointStatus(PointStatusEnum.POINT_STATUS_2.getCode());
        pointInfoDAO.updatePointInfo(updatePointInfo);
        return totalPointScore;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer pointInvalid(Long pointId) {
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        if(Objects.isNull(pointInfo)){
            log.error("铺位基本信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        if(PointStatusEnum.POINT_STATUS_6.getCode().equals(pointInfo.getPointStatus())){
            throw new ServiceException(ErrorCodeEnum.POINT_SIGNED);
        }
        PointInfoDO updatePoint = new PointInfoDO();
        updatePoint.setId(pointId);
        updatePoint.setPointStatus(PointStatusEnum.POINT_STATUS_7.getCode());
        pointInfoDAO.updatePointInfo(updatePoint);
        if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus())){
            rollbackSelectPoint(pointInfo.getShopId(), pointInfo.getId());
        }
        return pointRecommendDAO.updateRecommendStatus(pointId, PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_6, null);
    }

    /**
     * 回退选址状态
     * @return
     */
    private void rollbackSelectPoint(Long shopId, Long pointId){
        //店铺回退待带选址
        shopInfoDAO.unbindPoint(shopId);
        //铺位回退
        pointInfoDAO.recyclePoint(pointId);
        //回到待选址状态
        shopStageInfoDAO.updateShopStageInfo(shopId, ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_10);
        //租赁合同回到未开始
        Integer result = shopStageInfoDAO.updateShopStageToNotStarted(shopId, ShopSubStageEnum.SHOP_STAGE_2);
        if(result > CommonConstants.ZERO){
            //删除租赁合同
            shopRentInfoDAO.deleteRentContractByShopId(shopId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer pointUnbind(Long pointId) {
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        if(Objects.isNull(pointInfo)){
            log.error("铺位基本信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        if(PointStatusEnum.POINT_STATUS_6.getCode().equals(pointInfo.getPointStatus())){
            throw new ServiceException(ErrorCodeEnum.POINT_SIGNED);
        }
        if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus())){
            rollbackSelectPoint(pointInfo.getShopId(), pointInfo.getId());
        }
        //将已选择、已被他人选择的状态更新成待选泽
        return pointRecommendDAO.updateRecommendStatusByStatusAndPointId(pointId, PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_1, Arrays.asList(PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_2, PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_3));
    }

    @Override
    public Integer addMapEvaluationReport(AddMapEvaluationReportRequest request) {
        PointDetailInfoDO pointDetailInfo = pointDetailInfoDAO.getPointDetailInfoByPointId(request.getPointId());
        if(Objects.isNull(pointDetailInfo)){
            log.error("铺位基本信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        PointDetailInfoDO updatePoint = new PointDetailInfoDO();
        updatePoint.setId(pointDetailInfo.getId());
        updatePoint.setMapEvaluationReport(request.getMapEvaluationReport());
        return pointDetailInfoDAO.updatePointDetailInfo(updatePoint);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer submitAudit(SubmitPointAuditRequest request) {
        Long pointId = request.getPointId();
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        if(Objects.isNull(pointInfo)){
            log.error("铺位基本信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        PointDetailInfoDO pointDetailInfo = pointDetailInfoDAO.getPointDetailInfoByPointId(pointId);
        if(Objects.isNull(pointDetailInfo)){
            log.error("铺位详细信息不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        int submitAuditCount = pointInfo.getSubmitAuditCount() + 1;
        PointInfoDO updatePoint = new PointInfoDO();
        updatePoint.setId(pointId);
        updatePoint.setPointStatus(PointStatusEnum.POINT_STATUS_3.getCode());
        updatePoint.setSubmitAuditCount(submitAuditCount);
        PointDetailInfoDO updatePointDetail = new PointDetailInfoDO();
        updatePointDetail.setId(pointDetailInfo.getId());
        updatePointDetail.setDevelopmentManagerSign(request.getDevelopmentManagerSign());
        updatePointDetail.setDevelopmentManagerSignTime(new Date());
        pointDetailInfoDAO.updatePointDetailInfo(updatePointDetail);
        //处理子任务审核记录表
        AuditSettingVO auditSetting = getAuditSetting();
        if(Objects.isNull(auditSetting)){
            throw new ServiceException(ErrorCodeEnum.POINT_AUDIT_NOT_SETTING);
        }
        List<AuditNodeDTO> auditNode = dealAuditNode(auditSetting, pointInfo.getRegionId(), pointInfo.getDevelopmentManager());
        //获取审批节点上的数据
        List<PointAuditRecordDO> recordList = AuditNodeDTO.convertDO(pointId, submitAuditCount, auditNode);
        pointAuditRecordDAO.addPointAuditRecord(recordList);
        Map<Integer, PointAuditRecordDO> pointAuditRecordMap = recordList.stream().collect(Collectors.toMap(k -> k.getNodeNo(), v -> v));
        dealNextAuditRecord(pointInfo, pointAuditRecordMap, NodeNoEnum.NODE_NO_0.getCode());
        return pointInfoDAO.updatePointInfo(updatePoint);
    }

    @Override
    public Integer auditSetting(AuditSettingRequest request) {
        String cacheKey = MessageFormat.format(AUDIT_SETTING_KEY, enterpriseId);
        request.setSecondApproval(Arrays.asList(UserAndPositionRequest.convert("position", null, "战区营运")));
        redisUtilPool.setString(cacheKey, JSONObject.toJSONString(request));
        return null;
    }

    @Override
    public AuditSettingVO getAuditSetting() {
        String cacheKey = MessageFormat.format(AUDIT_SETTING_KEY, enterpriseId);
        String auditSetting = redisUtilPool.getString(cacheKey);
        if(StringUtils.isBlank(auditSetting)){
            return null;
        }
        return JSONObject.parseObject(auditSetting, AuditSettingVO.class);
    }

    @Override
    public List<String> getTodoUserList(Long pointId) {
        return pointTodoInfoDAO.getTodoUserList(pointId);
    }

    @Override
    public Integer operationUserAudit(String userId, OperationAuditRequest request) {
        return null;
    }


    /**
     * 初始化上传租赁合同阶段
     * @param pointInfo
     */
    private void initUploadRentContract(PointInfoDO pointInfo) {
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(pointInfo.getLineId());
        ShopInfoDO updateShopInfo = new ShopInfoDO();
        updateShopInfo.setId(pointInfo.getShopId());
        updateShopInfo.setRegionId(pointInfo.getRegionId());
        updateShopInfo.setShopName(pointInfo.getPointName());
        shopInfoDAO.updateShopInfo(updateShopInfo);
        shopStageInfoDAO.batchUpdateShopStageStatus(pointInfo.getShopId(), Arrays.asList(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_12, ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_20));
        Map<String, String> templateParam = new HashMap<>();
        templateParam.put("pointName", pointInfo.getAddress());
    }

    /**
     * 处理下一个节点的审批记录
     * @param pointInfo
     * @param pointAuditRecordMap
     * @param currentNo
     * @return
     */
    private Integer dealNextAuditRecord(PointInfoDO pointInfo, Map<Integer, PointAuditRecordDO> pointAuditRecordMap, Integer currentNo){
        Integer result = CommonConstants.ZERO;
        PointAuditRecordDO nextAuditRecord = getNextAuditRecord(currentNo, pointAuditRecordMap);
        if(Objects.nonNull(nextAuditRecord)){
            pointAuditRecordDAO.updatePointAuditRecord(PointAuditRecordDO.convert(nextAuditRecord.getId(), new Date()));
            //审批通过的情况下 生成下一个节点的待办数据
            pointTodoInfoDAO.addPointTodoInfo(PointAuditRecordDO.convertTODO(nextAuditRecord));
            List<String> sendMessageUserIds = JSONObject.parseArray(nextAuditRecord.getHandlerUserIds(), String.class);
            Map<String, String> messageMap = new HashMap<>();
            messageMap.put("pointId", String.valueOf(pointInfo.getId()));
            messageMap.put("pointName", pointInfo.getPointName());
            messageMap.put("pointAddress", pointInfo.getAddress());
            commonService.sendMessage(sendMessageUserIds, MessageEnum.MESSAGE_13, messageMap);
        }else{
            PointInfoDO updatePoint = new PointInfoDO();
            updatePoint.setId(pointInfo.getId());
            //没有下一节点  审批通过
            updatePoint.setPointStatus(PointStatusEnum.POINT_STATUS_5.getCode());
            updatePoint.setStorageStatus(StorageStatusEnum.IN_STORAGE.getCode());
            if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus())){
                initUploadRentContract(pointInfo);
            }
            Map<String, String> messageMap = new HashMap<>();
            messageMap.put("pointId", String.valueOf(pointInfo.getId()));
            messageMap.put("pointName", pointInfo.getPointName());
            messageMap.put("pointAddress", pointInfo.getAddress());
            commonService.sendMessage(Arrays.asList(pointInfo.getDevelopmentManager()), MessageEnum.MESSAGE_11, messageMap);
            result = pointInfoDAO.updatePointInfo(updatePoint);
        }
        return result;
    }

    /**
     * 铺位审核拒绝处理
     * @param pointInfo
     * @param reason
     * @return
     */
    private Integer auditRejectDeal(PointInfoDO pointInfo, String reason){
        Long pointId = pointInfo.getId();
        PointInfoDO pointInfoUpdate = new PointInfoDO();
        pointInfoUpdate.setId(pointId);
        pointInfoUpdate.setPointStatus(PointStatusEnum.POINT_STATUS_2.getCode());
        pointInfoUpdate.setStorageStatus(StorageStatusEnum.NOT_IN_STORAGE.getCode());
        //删除剩余未完成的审核记录
        pointAuditRecordDAO.deletePointAuditRecord(pointId, pointInfo.getSubmitAuditCount());
        Map<String, String> messageMap = new HashMap<>();
        messageMap.put("pointId", String.valueOf(pointInfo.getId()));
        messageMap.put("pointName", pointInfo.getPointName());
        messageMap.put("pointAddress", pointInfo.getAddress());
        messageMap.put("reason", reason);
        commonService.sendMessage(Arrays.asList(pointInfo.getDevelopmentManager()), MessageEnum.MESSAGE_12, messageMap);
        return pointInfoDAO.updatePointInfo(pointInfoUpdate);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer audit(String userId, PointAuditRequest request) {
        if(!request.check()){
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        Long pointId = request.getPointId();
        PointTodoInfoDO pointTodo = pointTodoInfoDAO.getPointToDoByUserIdAndPointId(userId, pointId);
        if(Objects.isNull(pointTodo)){
            log.info("该用户没有待办数据");
            throw new ServiceException(ErrorCodeEnum.USER_NOT_TODO_AUDIT);
        }
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        if(Objects.isNull(pointInfo)){
            log.info("铺位不存在");
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        AuditStatusEnum auditStatus = AuditStatusEnum.getByCode(request.getAuditStatus());
        //更新当前待办
        pointTodoInfoDAO.updatePointTodoInfo(pointId, pointTodo.getNodeNo(), pointInfo.getSubmitAuditCount(), userId);
        Map<Integer, PointAuditRecordDO> pointAuditRecordMap = pointAuditRecordDAO.getPointAuditRecordMap(pointId, pointInfo.getSubmitAuditCount());
        PointAuditRecordDO pointAuditRecord = pointAuditRecordMap.get(pointTodo.getNodeNo());
        if(Objects.isNull(pointAuditRecord)){
            log.info("铺位处理记录中的数据不对");
            throw new ServiceException(ErrorCodeEnum.POINT_AUDIT_NODE_ERROR);
        }
        NodeNoEnum nodeNoEnum = NodeNoEnum.getByCode(pointTodo.getNodeNo());
        PointAuditRecordDO auditRecord = PointAuditRecordDO.convert(pointAuditRecord.getId(), userId, auditStatus, request.getReason(), nodeNoEnum);
        pointAuditRecordDAO.updatePointAuditRecord(auditRecord);
        if(AuditStatusEnum.REJECT.equals(auditStatus)){
            return auditRejectDeal(pointInfo, request.getReason());
        }
        //处理下一节点任务及更新point状态
        return dealNextAuditRecord(pointInfo, pointAuditRecordMap, pointTodo.getNodeNo());
    }

    @Override
    public Integer turnDevelopmentManager(TurnDevelopmentManagerRequest request) {
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(request.getPointId());
        if(Objects.isNull(pointInfo)){
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus()) || PointStatusEnum.POINT_STATUS_6.getCode().equals(pointInfo.getPointStatus())){
            throw new ServiceException(ErrorCodeEnum.NOT_ALLOW_OPERATE);
        }
        if(PointStatusEnum.POINT_STATUS_7.getCode().equals(pointInfo.getPointStatus())){
            throw new ServiceException(ErrorCodeEnum.NOT_ALLOW_OPERATE);
        }
        pointInfo.setDevelopmentManager(request.getDevelopmentManager());
        return pointInfoDAO.updatePointInfo(pointInfo);
    }

    @Override
    public PageInfo<LinePointBaseInfoVO> getLinePage(PointLinePageRequest request) {
        Page<LineInfoDO> lineList = lineInfoDAO.getLinePageByDevelopmentManager(request);
        List<String> userPortraitList  = lineList.stream().filter(x -> StringUtils.isNotEmpty(x.getUserPortrait() )).map(LineInfoDO::getUserPortrait).collect(Collectors.toList());
        List<String> investmentManagerUserIds = lineList.stream().filter(x -> StringUtils.isNotEmpty(x.getInvestmentManager() )).map(LineInfoDO::getInvestmentManager).collect(Collectors.toList());
        List<Long> lineIds = lineList.stream().map(LineInfoDO::getId).collect(Collectors.toList());
        List<Long> wantShopAreaIds = lineList.stream().map(LineInfoDO::getWantShopAreaId).collect(Collectors.toList());
        Map<Long, Integer> recommendShopNumMap = pointRecommendDAO.getPushShopNumMap(lineIds);
        Map<Long, HyOpenAreaInfoDO> cityMap = hyOpenAreaInfoDAO.getCityMap(wantShopAreaIds);
        Map<Long, Integer> selectedShopNumMap = shopInfoDAO.getSelectedShopNumMap(lineIds);
        Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(investmentManagerUserIds);
        Map<Long, String> userPortraitMap = labelService.getUserPortraitMap(userPortraitList);
        List<LinePointBaseInfoVO> resultList = LinePointBaseInfoVO.convertList(lineList, userNameMap, userPortraitMap, cityMap, recommendShopNumMap, selectedShopNumMap);
        PageInfo resultPage = new PageInfo(lineList);
        resultPage.setList(resultList);
        return resultPage;
    }

    /**
     * 获取单个加盟商信息
     * @param lineId
     * @return
     */
    @Override
    public LinePointBaseInfoVO getLineInfo(Long lineId){
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(lineId);
        Map<Long, Integer> recommendShopNumMap = pointRecommendDAO.getPushShopNumMap(Arrays.asList(lineId));
        HyOpenAreaInfoDO cityArea = hyOpenAreaInfoDAO.selectById(lineInfo.getWantShopAreaId());
        Map<Long, Integer> selectedShopNumMap = shopInfoDAO.getSelectedShopNumMap(Arrays.asList(lineId));
        String userName = enterpriseUserDAO.getUserName(lineInfo.getInvestmentManager());
        Map<Long, String> userPortraitMap = labelService.getUserPortraitMap(Arrays.asList(lineInfo.getUserPortrait()));
        return LinePointBaseInfoVO.convert(lineInfo, userName, userPortraitMap, cityArea, recommendShopNumMap, selectedShopNumMap);
    }

    @Override
    public PointHomePageDataVO getMyPointData(String userId) {
        return pointInfoDAO.getMyPointData(userId);
    }

    @Override
    public PageInfo<PointPageVO> getMyPointPage(PointPageRequest request) {
        if(CollectionUtils.isNotEmpty(request.getRegionIds())){
            if(request.getRegionIds().contains(CommonConstants.ROOT_DEPT_ID_STR)){
                request.setRegionIds(null);
            }else{
                request.setRegionIds(regionService.getSubRegionIdsByRegionIds(request.getRegionIds()));
            }
        }
        List<PointPageVO> resultList = new ArrayList();
        Page<PointInfoDO> pointPage = pointInfoDAO.getMyPointPage(request);
        if(Objects.nonNull(pointPage) && CollectionUtils.isNotEmpty(pointPage.getResult())){
            List<Long> regionIds = pointPage.stream().map(PointInfoDO::getRegionId).distinct().collect(Collectors.toList());
            List<String> developmentManagers = pointPage.stream().map(PointInfoDO::getDevelopmentManager).distinct().collect(Collectors.toList());
            Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(developmentManagers);
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            resultList = PointPageVO.convertVO(pointPage.getResult(), userNameMap, regionNameMap);
        }
        PageInfo resultPage = new PageInfo(pointPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    @Override
    public PageInfo<PointPageVO> getTeamPointPage(AllPointPageRequest request){
        if(!sysRoleService.checkIsAdmin(request.getCurUserId())){
            request.setAuthRegionIds(userAuthMappingService.getAuthRegionIdAndSubRegionIdByUserId(request.getCurUserId()));
        }
        if(CollectionUtils.isNotEmpty(request.getRegionIds())){
            if(request.getRegionIds().contains(CommonConstants.ROOT_DEPT_ID_STR)){
                request.setRegionIds(null);
            }else{
                request.setRegionIds(regionService.getSubRegionIdsByRegionIds(request.getRegionIds()));
            }
        }
        if(Objects.nonNull(request.getPointStatus()) && PointStatusEnum.POINT_STATUS_3.getCode().equals(request.getPointStatus())){
            request.setPointStatus(PointStatusEnum.POINT_STATUS_4.getCode());
        }
        List<PointPageVO> resultList = new ArrayList();
        Page<PointInfoDO> pointPage = pointInfoDAO.getTeamPointPage(request);
        if(Objects.nonNull(pointPage) && CollectionUtils.isNotEmpty(pointPage.getResult())){
            List<Long> regionIds = pointPage.stream().map(PointInfoDO::getRegionId).distinct().collect(Collectors.toList());
            List<String> developmentManagers = pointPage.stream().map(PointInfoDO::getDevelopmentManager).distinct().collect(Collectors.toList());
            Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(developmentManagers);
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            resultList = PointPageVO.convertVO(pointPage.getResult(), userNameMap, regionNameMap);
        }
        PageInfo resultPage = new PageInfo(pointPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    @Override
    public List<PointAuditRecordVO> getPointAllAuditRecord(Long pointId) {
        List<PointAuditRecordDO> auditRecordList = pointAuditRecordDAO.getPointAllAuditRecord(pointId);
        if(CollectionUtils.isEmpty(auditRecordList)){
            return Lists.newArrayList();
        }
        List<String> userIds = auditRecordList.stream().map(o->JSONObject.parseArray(o.getHandlerUserIds(), String.class)).flatMap(Collection::stream).distinct().collect(Collectors.toList());
        Map<String, EnterpriseUserDO> userMap = enterpriseUserDAO.getUserInfoMap(userIds);
        return PointAuditRecordVO.convert(auditRecordList, userMap);
    }

    @Override
    public List<PointRecommendPageVO> getLineRecommendPointList(Long lineId) {
        List<PointRecommendDO> recommendPointList = pointRecommendDAO.getRecommendPointList(lineId);
        List<Long> pointIds = recommendPointList.stream().map(PointRecommendDO::getPointId).distinct().collect(Collectors.toList());
        List<PointInfoDO> pointList = pointInfoDAO.getPointListByIds(pointIds);
        List<Long> regionIds = pointList.stream().map(PointInfoDO::getRegionId).distinct().collect(Collectors.toList());
        List<String> developmentManagers = pointList.stream().map(PointInfoDO::getDevelopmentManager).distinct().collect(Collectors.toList());
        List<Long> shopIds = pointList.stream().map(PointInfoDO::getShopId).distinct().collect(Collectors.toList());
        List<Long> canSubmitRentContractShopIds = shopStageInfoDAO.getCanSubmitRentContractShopIds(shopIds);
        Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(developmentManagers);
        Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
        return PointRecommendPageVO.convertVO(recommendPointList, pointList, userNameMap, regionNameMap, canSubmitRentContractShopIds);
    }

    @Override
    public PageInfo<PointPageVO> getRecommendPointList(RecommendPointPageRequest request) {
        List<PointPageVO> resultList = new ArrayList();
        Page<PointInfoDO> pointPage = pointInfoDAO.getRecommendPointList(request);
        if(Objects.nonNull(pointPage) && CollectionUtils.isNotEmpty(pointPage.getResult())){
            List<Long> regionIds = pointPage.stream().map(PointInfoDO::getRegionId).distinct().collect(Collectors.toList());
            List<String> developmentManagers = pointPage.stream().map(PointInfoDO::getDevelopmentManager).distinct().collect(Collectors.toList());
            Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(developmentManagers);
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            resultList = PointPageVO.convertVO(pointPage.getResult(), userNameMap, regionNameMap);
        }
        PageInfo resultPage = new PageInfo(pointPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    @Override
    public Integer lineRecommendPoint(LineRecommendPointRequest request) {
        List<Long> pointIds = request.getPointIds();
        List<PointInfoDO> pointList = pointInfoDAO.getPointListByIds(pointIds);
        List<PointInfoDO> selectList = pointList.stream().filter(o -> SelectStatusEnum.SELECT_STATUS_1.getCode().equals(o.getSelectStatus())).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(selectList)){
            String pointNames = selectList.stream().map(PointInfoDO::getPointName).collect(Collectors.joining(","));
            throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, pointNames + "，已经被选");
        }
        List<PointInfoDO> invalidList = pointList.stream().filter(o -> PointStatusEnum.POINT_STATUS_7.getCode().equals(o.getPointStatus())).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(invalidList)){
            String pointNames = invalidList.stream().map(PointInfoDO::getPointName).collect(Collectors.joining(","));
            throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, pointNames + "，已失效");
        }
        List<PointRecommendDO> recommendPointList = pointRecommendDAO.getRecommendPointList(request.getLineId());
        if(CollectionUtils.isNotEmpty(recommendPointList)){
            List<PointRecommendDO> recommendList = recommendPointList.stream().filter(o -> PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_1.getCode().equals(o.getStatus()) ||
                    PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_2.getCode().equals(o.getStatus()) ||
                    PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_4.getCode().equals(o.getStatus()))
                    .filter(o->request.getPointIds().contains(o.getPointId())).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(recommendList)){
                throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, "铺位已推送，请勿重复推送");
            }
            List<PointRecommendDO> selectedList = recommendPointList.stream().filter(o -> PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_3.getCode().equals(o.getStatus())).filter(o->request.getPointIds().contains(o.getPointId())).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(selectedList)){
                throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, "铺位已选，请勿重复推送");
            }
        }
        List<PointRecommendDO> recommendList = request.convertList();
        return pointRecommendDAO.addRecommendPoint(recommendList);
    }

    @Override
    public Integer pointRecommendLine(PointRecommendLineRequest request) {
        Long pointId = request.getPointId();
        PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
        if(Objects.isNull(pointInfo)){
            throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
        }
        if(PointStatusEnum.POINT_STATUS_7.getCode().equals(pointInfo.getPointStatus())){
            throw new ServiceException(ErrorCodeEnum.POINT_IS_INVALID);
        }
        if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus())){
            throw new ServiceException(ErrorCodeEnum.POINT_SELECTED);
        }
        List<PointRecommendDO> recommendPointList = pointRecommendDAO.getRecommendPointListByPointId(pointId);
        if(CollectionUtils.isNotEmpty(recommendPointList)){
            List<PointRecommendDO> recommendList = recommendPointList.stream().filter(o -> PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_2.getCode().equals(o.getStatus()) ||
                    PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_3.getCode().equals(o.getStatus()) ||
                    PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_4.getCode().equals(o.getStatus()))
                    .filter(o->request.getLineIds().contains(o.getLineId())).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(recommendList)){
                throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, "推送失败，铺位已被选");
            }
            List<Long> lineIds = recommendPointList.stream().filter(o -> PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_1.getCode().equals(o.getStatus())).filter(o->request.getLineIds().contains(o.getLineId())).map(PointRecommendDO::getLineId).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(lineIds)){
                lineIds.retainAll(request.getLineIds());
                if(CollectionUtils.isNotEmpty(lineIds)){
                    throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE, "请勿重复推送");
                }
            }
        }
        List<PointRecommendDO> recommendList = request.convertList();
        return pointRecommendDAO.addRecommendPoint(recommendList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer turnLine(TurnLineRequest request) {
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(request.getLineId());
        Long lineId = request.getLineId();
        //更改线索中的拓展经理
        LineInfoDO updateLineInfo = new LineInfoDO();
        updateLineInfo.setId(lineId);
        updateLineInfo.setDevelopmentManager(request.getDevelopmentManager());
        lineInfoDAO.updateLineInfo(updateLineInfo);
        //更新已被选择的铺位的拓展经理
        pointInfoDAO.updateSelectedDevelopmentManager(lineId, request.getDevelopmentManager());
        String wantShopName = hyOpenAreaInfoDAO.selectNameMapById(lineInfo.getWantShopAreaId());

        Map<String, String> messageMap = new HashMap<>();
        messageMap.put("lineId", String.valueOf(lineId));
        messageMap.put("partnerUsername", lineInfo.getUsername());
        messageMap.put("partnerMobile", lineInfo.getMobile());
        messageMap.put("wantShopName", wantShopName);
        commonService.sendMessage(Arrays.asList(request.getDevelopmentManager()), MessageEnum.MESSAGE_14, messageMap);
        //删除未选择的推荐铺位
        return pointRecommendDAO.turnLineUpdateRecommendStatus(lineId, request.getDevelopmentManager());
    }

    @Override
    public Integer updateWantShopNum(UpdateWantShopNumRequest request) {
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(request.getLineId());
        if(Objects.isNull(lineInfo)){
            throw new ServiceException(ErrorCodeEnum.LINE_ID_IS_NOT_EXIST);
        }
        if(!WorkflowStageEnum.INTENT.getCode().equals(lineInfo.getWorkflowStage())){
            throw new ServiceException(ErrorCodeEnum.NOT_ALLOW_MODIFY_WANT_SHOP_NUM);
        }
        LineInfoDO updateLine = new LineInfoDO();
        updateLine.setId(request.getLineId());
        updateLine.setWantShopNum(request.getWantShopNum());
        return lineInfoDAO.updateLineInfo(updateLine);
    }

    @Override
    public PageInfo<PointPageVO> getTodoList(PointTodoPageRequest request) {
        Page<PointInfoDO> pointPage = pointTodoInfoDAO.getUserTodoList(request);
        List<PointPageVO> resultList = new ArrayList<>();
        if(Objects.nonNull(pointPage) && CollectionUtils.isNotEmpty(pointPage.getResult())){
            List<Long> regionIds = pointPage.stream().map(PointInfoDO::getRegionId).distinct().collect(Collectors.toList());
            List<String> developmentManagers = pointPage.stream().map(PointInfoDO::getDevelopmentManager).distinct().collect(Collectors.toList());
            Map<String, String> userNameMap = enterpriseUserDAO.getUserNameMap(developmentManagers);
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            resultList = PointPageVO.convertVO(pointPage.getResult(), userNameMap, regionNameMap);
        }
        PageInfo resultPage = new PageInfo(pointPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    @Override
    public PageInfo<MiniPointPageVO> getLineRecommendPointPage(MiniPointPageRequest request) {
        Page<MiniPointPageDTO> pointPage = pointRecommendDAO.getLineRecommendPointPage(request);
        List<MiniPointPageVO> resultList = new ArrayList<>();
        if(Objects.nonNull(pointPage) && CollectionUtils.isNotEmpty(pointPage.getResult())){
            List<Long> regionIds = pointPage.getResult().stream().map(MiniPointPageDTO::getRegionId).distinct().collect(Collectors.toList());
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            resultList = MiniPointPageVO.convertVO(pointPage, regionNameMap, request.getLineId());
        }
        PageInfo resultPage = new PageInfo(pointPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer lineSelectPoint(SelectPointRequest request) {
        Long pointId = request.getPointId(), shopId = request.getShopId(), lineId = request.getLineId();
        String lockKey = MessageFormat.format(POINT_SELECT_KEY, enterpriseId, pointId);
        if(!redisUtilPool.setNxExpire(lockKey, JSONObject.toJSONString(request), 30*1000)){
            throw new ServiceException(ErrorCodeEnum.POINT_IS_LOCK);
        }
        try {
            ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(shopId);
            if(Objects.isNull(shopInfo)){
                throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
            }
            if(!ShopStageEnum.SHOP_STAGE_1.getShopStage().equals(shopInfo.getShopStage())){
                throw new ServiceException(ErrorCodeEnum.SHOP_STAGE_NOT_OPERATE);
            }
            if(Objects.nonNull(shopInfo.getPointId())){
                throw new ServiceException(ErrorCodeEnum.SHOP_IS_SELECTED);
            }
            PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
            if(Objects.isNull(pointInfo)){
                throw new ServiceException(ErrorCodeEnum.POINT_NOT_EXIST);
            }
            if(SelectStatusEnum.SELECT_STATUS_1.getCode().equals(pointInfo.getSelectStatus())){
                if(lineId.equals(pointInfo.getLineId())){
                   throw new ServiceException(ErrorCodeEnum.POINT_ALREADY_SELECT);
                }
                throw new ServiceException(ErrorCodeEnum.POINT_IS_SELECTED);
            }
            PointInfoDO updatePoint = new PointInfoDO();
            updatePoint.setId(pointId);
            updatePoint.setSelectStatus(SelectStatusEnum.SELECT_STATUS_1.getCode());
            updatePoint.setLineId(lineId);
            updatePoint.setShopId(shopId);
            pointInfoDAO.updatePointInfo(updatePoint);
            ShopInfoDO updateShop = new ShopInfoDO();
            updateShop.setId(shopId);
            updateShop.setShopName(pointInfo.getPointName());
            updateShop.setPointId(pointId);
            updateShop.setRegionId(pointInfo.getRegionId());
            shopInfoDAO.updateShopInfo(updateShop);
            ShopSubStageStatusEnum selectStatus = ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_11;
            PointDetailInfoDO updateDetail = new PointDetailInfoDO();
            updateDetail.setPointId(pointId);
            updateDetail.setLineSign(request.getLineSign());
            updateDetail.setLineSignTime(new Date());
            pointDetailInfoDAO.updatePointDetailInfo(updateDetail);
            List<ShopSubStageStatusEnum> updateStatusList = new ArrayList<>();
            //如果铺位是已审核 则进入上传租赁合同状态
            if(PointStatusEnum.POINT_STATUS_5.getCode().equals(pointInfo.getPointStatus())){
                selectStatus = ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_12;
                updateStatusList.add(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_20);
                Map<String, String> templateParam = new HashMap<>();
                templateParam.put("pointName", pointInfo.getAddress());
                LineInfoDO lineInfo = lineInfoDAO.getLineInfo(request.getLineId());
            }
            updateStatusList.add(selectStatus);
            shopStageInfoDAO.batchUpdateShopStageStatus(shopId, updateStatusList);
            return pointRecommendDAO.updateStatusByPointIdAndLineId(pointId, lineId);
        } catch (ServiceException e) {
            throw e;
        } finally {
            redisUtilPool.delKey(lockKey);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer lineRejectPoint(RejectPointRequest request){
        return pointRecommendDAO.rejectPoint(request.getLineId(), request.getPointId(), request.getReason());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long miniAddPointDetailInfo(MiniAddPointRequest request) {
        Long lineId = request.getCurLineId();
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(lineId);
        if(Objects.isNull(lineInfo)){
            throw new ServiceException(ErrorCodeEnum.LINE_ID_IS_NOT_EXIST);
        }
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(request.getShopId());
        if(Objects.isNull(shopInfo)){
            throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
        }
        if(Objects.nonNull(shopInfo.getPointId())){
            throw new ServiceException(ErrorCodeEnum.SHOP_IS_SELECTED);
        }
        PointDetailInfoDO pointDetailInfo = MiniAddPointRequest.convertDO(request);
        PointInfoDO pointInfo = MiniAddPointRequest.convertPointDO(request);
        pointInfo.setRegionId(lineInfo.getRegionId());
        pointInfo.setLineId(lineId);
        pointInfo.setSelectStatus(SelectStatusEnum.SELECT_STATUS_1.getCode());
        pointInfo.setDevelopmentManager(lineInfo.getDevelopmentManager());
        pointInfo.setDevelopmentTime(new Date());
        pointInfo.setPointSource(PointSourceEnum.POINT_SOURCE_2.getCode());
        pointInfo.setPointCode(generateCode());
        Long pointId = pointInfoDAO.addPointInfo(pointInfo);
        pointDetailInfo.setPointId(pointId);
        pointDetailInfoDAO.addPointDetailInfo(pointDetailInfo);
        shopInfo.setShopName(pointInfo.getPointName());
        shopInfo.setPointId(pointId);
        shopInfoDAO.updateShopInfo(shopInfo);
        PointRecommendDO pointRecommendDO = new PointRecommendDO();
        pointRecommendDO.setLineId(lineId);
        pointRecommendDO.setDevelopmentManager(lineInfo.getDevelopmentManager());
        pointRecommendDO.setPointId(pointId);
        pointRecommendDO.setStatus(PointRecommendStatusEnum.POINT_RECOMMEND_STATUS_2.getCode());
        //推荐列表新增
        pointRecommendDAO.addRecommendPoint(Lists.newArrayList(pointRecommendDO));
        //更新店铺所处阶段
        shopStageInfoDAO.updateShopStageInfo(shopInfo.getId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_11);
        PointInfoDO updatePoint = new PointInfoDO();
        updatePoint.setId(pointId);
        updatePoint.setShopId(shopInfo.getId());
        pointInfoDAO.updatePointInfo(updatePoint);
        return pointId;
    }

    @Override
    public Integer uploadRentContract(AddRentContractRequest request){
        if(!request.check()){
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        Long pointId = request.getPointId(), shopId = request.getShopId();
        if(Objects.isNull(pointId) && Objects.nonNull(shopId)){
            ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(shopId);
            pointId = shopInfo.getPointId();
        }
        if(Objects.nonNull(pointId) && Objects.isNull(shopId)){
            PointInfoDO pointInfo = pointInfoDAO.getPointInfoById(pointId);
            shopId = pointInfo.getShopId();
        }
        ShopStageInfoDO shopSubStageInfo = shopStageInfoDAO.getShopSubStageInfo(shopId, ShopSubStageEnum.SHOP_STAGE_2);
        if(Objects.isNull(shopSubStageInfo)){
            throw new ServiceException(ErrorCodeEnum.SHOP_STAGE_ERROR);
        }
        List<Integer> operateStatusList = Lists.newArrayList(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_20.getShopSubStageStatus(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_22.getShopSubStageStatus());
        if(!operateStatusList.contains(shopSubStageInfo.getShopSubStageStatus())){
            throw new ServiceException(ErrorCodeEnum.SHOP_STAGE_NOT_OPERATE);
        }
        //是否存在租赁合同
        ShopRentInfoDO rentContract = shopRentInfoDAO.getRentContractByShopId(shopId);
        ShopRentInfoDO shopRentInfo = AddRentContractRequest.convertDO(request);
        shopRentInfo.setShopId(shopId);
        shopRentInfo.setPointId(pointId);
        if(Objects.isNull(rentContract)){
            shopRentInfoDAO.addShopRentInfo(shopRentInfo);
        }else{
            shopRentInfo.setId(rentContract.getId());
            shopRentInfoDAO.updateRentContract(shopRentInfo);
        }
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(shopSubStageInfo.getLineId());
        Map<String, String> messageMap = new HashMap<>();
        messageMap.put("lineId", String.valueOf(lineInfo.getId()));
        messageMap.put("partnerUsername", lineInfo.getUsername());
        messageMap.put("submitTime", DateUtils.parseDateToStr(DateUtils.NOTICE_DATE, new Date()));
        commonService.sendMessage(Arrays.asList(lineInfo.getDevelopmentManager()), MessageEnum.MESSAGE_15, messageMap);
        return shopStageInfoDAO.updateShopStageInfo(shopId, ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_21);
    }

    @Override
    public ShopRentInfoVO getRentContractDetail(Long shopId) {
        ShopRentInfoDO rentContract = shopRentInfoDAO.getRentContractByShopId(shopId);
        if(Objects.isNull(rentContract)){
            return null;
        }
        ShopRentInfoVO result = ShopRentInfoVO.build(rentContract);
        ShopStageInfoDO shopSubStageInfo = shopStageInfoDAO.getShopSubStageInfo(shopId, ShopSubStageEnum.SHOP_STAGE_2);
        result.setStatus(shopSubStageInfo.getShopSubStageStatus());
        boolean isAudit = ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_22.getShopSubStageStatus().equals(shopSubStageInfo.getShopSubStageStatus()) ||
                ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_23.getShopSubStageStatus().equals(shopSubStageInfo.getShopSubStageStatus());
        if(Objects.nonNull(shopSubStageInfo.getAuditId()) && isAudit){
            //当前是审核过的状态才获取原因
            ShopAuditInfoDO auditInfo = shopAuditInfoDAO.getAuditInfo(shopSubStageInfo.getAuditId());
            result.setAuditInfo(AuditInfoVO.convertVO(auditInfo));
        }
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(rentContract.getShopId());
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(shopInfo.getLineId());
        EnterpriseUserDO enterpriseUserDO = enterpriseUserDAO.getUserInfoById(lineInfo.getDevelopmentManager());
        result.setApprover(Objects.isNull(enterpriseUserDO) ? null : enterpriseUserDO.getName());
        return result;
    }

    @Override
    public Integer auditRentContract(AuditRentContractRequest request) {
        Long shopId = request.getShopId();
        ShopInfoDO shopInfo = shopInfoDAO.getShopInfo(request.getShopId());
        if(Objects.isNull(shopInfo)){
            throw new ServiceException(ErrorCodeEnum.SHOP_NOT_EXIST);
        }
        if(!ShopStageEnum.SHOP_STAGE_1.getShopStage().equals(shopInfo.getShopStage())){
            throw new ServiceException(ErrorCodeEnum.SHOP_STAGE_NOT_OPERATE);
        }
        LineInfoDO lineInfo = lineInfoDAO.getLineInfo(shopInfo.getLineId());
        if(!request.getOperateUserId().equals(lineInfo.getDevelopmentManager())){
            throw new ServiceException(ErrorCodeEnum.NO_PERMISSION);
        }
        Long auditId = shopAuditInfoDAO.addAuditInfo(AuditRentContractRequest.convert(request, AuditTypeEnum.UPLOAD_RENT_CONTRACT));

        ShopSubStageStatusEnum subStageStatus = AuditResultTypeEnum.PASS.getCode().equals(request.getResultType()) ? ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_23 : ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_22;
        if(AuditResultTypeEnum.REJECT.getCode().equals(request.getResultType())){
            //commonService.sendSms(lineInfo.getMobile(), SMSMsgEnum.RENT_CONTRACT_AUDIT_FAIL, null);
        }
        if(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_23.equals(subStageStatus)){
            //审核通过铺位变为已签约
            PointInfoDO updatePoint = new PointInfoDO();
            updatePoint.setId(shopInfo.getPointId());
            updatePoint.setPointStatus(PointStatusEnum.POINT_STATUS_6.getCode());
            pointInfoDAO.updatePointInfo(updatePoint);
            ShopInfoDO updateShop = new ShopInfoDO();
            updateShop.setId(shopId);
            updateShop.setShopStage(ShopStageEnum.SHOP_STAGE_2.getShopStage());
            List<UserRoleEnum> roleList = Arrays.asList(UserRoleEnum.THEATER_MANAGER, UserRoleEnum.OPERATIONS_MANAGER, UserRoleEnum.REGION_MANAGER);
            String shopManagerUserId = sysRoleService.getUserIdByRegionIdWithRolePriority(shopInfo.getRegionId(), roleList);
            if(StringUtils.isBlank(shopManagerUserId)){
                shopManagerUserId = userAuthMappingService.getShopManagerUserId();
            }
            updateShop.setShopManagerUserId(shopManagerUserId);
            shopInfoDAO.updateShopInfo(updateShop);
            //发送工作通知
            Map<String, String> requestMap = new HashMap<>();
            requestMap.put("partnerName",lineInfo.getUsername());
            requestMap.put("partnerMobile",lineInfo.getMobile());
            requestMap.put("lineId",String.valueOf(lineInfo.getId()));
            requestMap.put("shopId",String.valueOf(shopId));
//            if (Objects.nonNull(shopInfo.getShopName())) {
//                requestMap.put("storeName",shopInfo.getShopName());
//                commonService.sendMessage(Arrays.asList(lineInfo.getInvestmentManager()),MessageEnum.MESSAGE_16,requestMap);
//            }else {
//                commonService.sendMessage(Arrays.asList(lineInfo.getInvestmentManager()),MessageEnum.MESSAGE_16_1,requestMap);
//            }
        }
        return shopStageInfoDAO.updateShopStageAndAuditInfo(shopId, subStageStatus, auditId);
    }

    @Override
    public Integer updateRentContract(UpdateRentContractRequest request){
        if(!request.check()){
            throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR);
        }
        ShopRentInfoDO shopRentInfo = UpdateRentContractRequest.convertDO(request);
        ShopStageInfoDO shopSubStageInfo = shopStageInfoDAO.getShopSubStageInfo(request.getShopId(), ShopSubStageEnum.SHOP_STAGE_2);
        if(ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_22.getShopSubStageStatus().equals(shopSubStageInfo.getShopSubStageStatus())){
            shopStageInfoDAO.updateShopStageAndAuditInfo(shopRentInfo.getShopId(), ShopSubStageStatusEnum.SHOP_SUB_STAGE_STATUS_21, null);
            LineInfoDO lineInfo = lineInfoDAO.getLineInfo(shopSubStageInfo.getLineId());
            Map<String, String> messageMap = new HashMap<>();
            messageMap.put("lineId", String.valueOf(lineInfo.getId()));
            messageMap.put("partnerUsername", lineInfo.getUsername());
            messageMap.put("submitTime", DateUtils.parseDateToStr(DateUtils.NOTICE_DATE, new Date()));
            commonService.sendMessage(Arrays.asList(lineInfo.getDevelopmentManager()), MessageEnum.MESSAGE_15, messageMap);
        }
        return shopRentInfoDAO.updateRentContract(shopRentInfo);
    }

    @Override
    public PageInfo<PointToDoVO> getSelectPointToDoPage(String userId, Integer pageNumber, Integer pageSize) {
        PointTodoPageRequest request = new PointTodoPageRequest();
        request.setDevelopmentManager(userId);
        request.setPageNum(pageNumber);
        request.setPageSize(pageSize);
        Page<PointInfoDO> pointPage = pointTodoInfoDAO.getUserTodoList(request);
        List<PointToDoVO> resultList = new ArrayList<>();
        if(Objects.nonNull(pointPage) && CollectionUtils.isNotEmpty(pointPage.getResult())){
            List<Long> regionIds = pointPage.stream().map(PointInfoDO::getRegionId).distinct().collect(Collectors.toList());
            List<Long> pointIds = pointPage.stream().map(PointInfoDO::getId).collect(Collectors.toList());
            //获取提交时间
            Map<Long, Date> submitTimeMap = pointAuditRecordDAO.getPointSubmitTimeMap(pointIds);
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            resultList = PointToDoVO.convertVO(pointPage.getResult(), regionNameMap, submitTimeMap);
        }
        PageInfo resultPage = new PageInfo(pointPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    @Override
    public PageInfo<RentInfoToDoVO> getRentContractToDoPage(String userId, Integer pageNumber, Integer pageSize) {
        Page<RentInfoToDoVO> todoPage = shopStageInfoDAO.getRentContractToDoPage(userId, pageNumber, pageSize);
        List<RentInfoToDoVO> resultList = null;
        if(Objects.nonNull(todoPage) && CollectionUtils.isNotEmpty(todoPage.getResult())){
            List<Long> shopIds = todoPage.getResult().stream().map(RentInfoToDoVO::getShopId).collect(Collectors.toList());
            List<ShopInfoDO> shopList = shopInfoDAO.getShopListByIds(shopIds);
            Map<Long, ShopInfoDO> shopPointMap = shopList.stream().collect(Collectors.toMap(k->k.getId(), Function.identity()));
            List<Long> regionIds = shopList.stream().map(ShopInfoDO::getRegionId).distinct().collect(Collectors.toList());
            List<Long> pointIds = shopList.stream().map(ShopInfoDO::getPointId).collect(Collectors.toList());
            List<PointInfoDO> pointList = pointInfoDAO.getPointListByIds(pointIds);
            Map<Long, PointInfoDO> pointMap = ListUtils.emptyIfNull(pointList).stream().collect(Collectors.toMap(k->k.getId(), Function.identity()));
            Map<Long, String> regionNameMap = regionService.getBelongWarRegionNameMap(regionIds);
            List<ShopRentInfoDO> rentContractList = shopRentInfoDAO.getRentContractByShopIds(shopIds);
            Map<Long, Date> rentContractSubmitTimeMap = ListUtils.emptyIfNull(rentContractList).stream().collect(Collectors.toMap(k->k.getShopId(), v->v.getCreateTime()));
            resultList = RentInfoToDoVO.convert(todoPage, shopPointMap, pointMap, regionNameMap, rentContractSubmitTimeMap);
        }
        PageInfo resultPage = new PageInfo(todoPage);
        resultPage.setList(resultList);
        return resultPage;
    }

    public List<AuditNodeDTO> dealAuditNode(AuditSettingVO auditSetting, Long regionId, String developmentManager) {
        List<String> roleIds = new ArrayList<>();
        //审核人
        Pair<List<String>, List<String>> firstApproval = getUserIdsAndPositionIds(auditSetting.getFirstApproval());
        if(CollectionUtils.isNotEmpty(firstApproval.getValue())){
            roleIds.addAll(firstApproval.getValue());
        }
        List<AuditNodeDTO> resultList = new ArrayList<>();
        Map<String, List<String>> userIdsMap = userAuthMappingService.getUserIdByRoleIdAndRegionId(roleIds, regionId);
        List<String> firstApprovalUserIds = getUserIdsByPositionIds(firstApproval, userIdsMap);
        resultList.add(new AuditNodeDTO(NodeNoEnum.NODE_NO_0.getCode(), PointAuditRecordDO.SUBMIT_TASK, Boolean.FALSE, Arrays.asList(developmentManager)));
        if(CollectionUtils.isNotEmpty(firstApprovalUserIds)){
            resultList.add(new AuditNodeDTO(NodeNoEnum.NODE_NO_1.getCode(), PointAuditRecordDO.RECEIVE_TASK, Boolean.TRUE, firstApprovalUserIds));
        }
        return resultList;
    }

    /**
     * 获取配置的userId 和 角色id
     * @param requests
     * @return
     */
    private Pair<List<String>, List<String>> getUserIdsAndPositionIds(List<UserAndPositionRequest> requests){
        List<String> positionIds = ListUtils.emptyIfNull(requests).stream().filter(o -> "position".equals(o.getType())).map(UserAndPositionRequest::getValue).collect(Collectors.toList());
        List<String> userIds = ListUtils.emptyIfNull(requests).stream().filter(o -> "person".equals(o.getType())).map(UserAndPositionRequest::getValue).collect(Collectors.toList());
        return Pair.of(userIds, positionIds);
    }

    /**
     * 获取userId
     * @param userIdsAndPositionIds
     * @param userIdsMap
     * @return
     */
    private List<String> getUserIdsByPositionIds(Pair<List<String>, List<String>> userIdsAndPositionIds, Map<String, List<String>> userIdsMap) {
        Set<String> userIds = new HashSet<>();
        if(CollectionUtils.isNotEmpty(userIdsAndPositionIds.getKey())){
            userIds.addAll(userIdsAndPositionIds.getKey());
        }
        if(CollectionUtils.isNotEmpty(userIdsAndPositionIds.getValue())){
            userIdsAndPositionIds.getValue().forEach(positionId -> {
                List<String> userIdList = userIdsMap.get(positionId);
                if(CollectionUtils.isNotEmpty(userIdList)){
                    userIds.addAll(userIdList);
                }
            });
        }
        return new ArrayList<>(userIds);
    }

    private PointAuditRecordDO getNextAuditRecord(Integer currentNodeNo, Map<Integer, PointAuditRecordDO> auditRecordMap){
        List<NodeNoEnum> nextNodeNoList = NodeNoEnum.getNextNodeNoList(currentNodeNo);
        if(CollectionUtils.isEmpty(nextNodeNoList)){
            return null;
        }
        for (NodeNoEnum nodeNoEnum : nextNodeNoList) {
            PointAuditRecordDO pointAuditRecord = auditRecordMap.get(nodeNoEnum.getCode());
            if(Objects.nonNull(pointAuditRecord)){
                return pointAuditRecord;
            }
        }
        return null;
    }

    /**
     * 生成code
     * @return
     */
    private String generateCode() {
        // 获取当前时间戳，格式化为YYYYMMddHHmmssSSS
        LocalDateTime now = LocalDateTime.now();
        String timestampStr = now.format(DateTimeFormatter.ofPattern("yyMMddHHmmssSSS"));
        // 组合成订单编号，这里假设订单编号格式为：时间戳-序列号
        return timestampStr;
    }
}
