package com.sonic.frog.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sonic.bear.lib.output.BaseUserInfoOutput;
import com.sonic.common.rpc.Page;
import com.sonic.daosupport.converter.PageConverter;
import com.sonic.frog.dao.AiUserHeartbeatRelationDao;
import com.sonic.frog.domain.entity.AiUser;
import com.sonic.frog.domain.entity.AiUserHeartbeatRelation;
import com.sonic.frog.domain.entity.BuyHeartbeatValueRecord;
import com.sonic.frog.domain.entity.HeartbeatLevelDict;
import com.sonic.frog.domain.input.BuyHeartbeatValInput;
import com.sonic.frog.domain.input.HeartbeatRelationListInput;
import com.sonic.frog.domain.input.HeartbeatRelationSwitchInput;
import com.sonic.frog.domain.output.*;
import com.sonic.frog.enums.HeartbeatLevelEnum;
import com.sonic.frog.event.inner.payload.AiUserStatPayload;
import com.sonic.frog.event.inner.payload.CalcHeartbeatLevelPayload;
import com.sonic.frog.service.*;
import com.sonic.frog.utils.BeanConver;
import com.sonic.frog.utils.KeyGenerator;
import com.sonic.frog.utils.LimitUtils;
import com.sonic.frog.utils.RedisKeyUtils;
import com.sonic.lion.lib.client.PayClient;
import com.sonic.lion.lib.enums.BizType;
import com.sonic.lion.lib.input.BalanceCheckoutInput;
import com.sonic.pigeon.lib.client.ImConversationClient;
import com.sonic.pigeon.lib.client.ImMessageClient;
import com.sonic.pigeon.lib.enums.ImMessageTypeEnum;
import com.sonic.pigeon.lib.input.ConversationExtensionInput;
import com.sonic.pigeon.lib.input.SendAiCustomerMessageInput;
import com.sonic.pigeon.lib.input.UpdateConversationInput;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.sonic.frog.enums.Constants.HEARTBEAT_VAL_PRICE;

/**
 * 用户与AI的心动关系服务实现类
 */
@Service
@Slf4j
public class AiUserHeartbeatRelationServiceImpl extends ServiceImpl<AiUserHeartbeatRelationDao, AiUserHeartbeatRelation> implements AiUserHeartbeatRelationService {

    @Autowired
    private UserService userService;
    @Autowired
    private AiUserSearchService aiUserSearchService;
    @Autowired
    private HeartbeatLevelDictService heartbeatLevelDictService;
    @Autowired
    private ImConversationClient imConversationClient;
    @Autowired
    private ImMessageClient imMessageClient;
    @Autowired
    private BuyHeartbeatValueRecordService buyHeartbeatValueRecordService;
    @Autowired
    private CommonSendMqService commonSendMqService;
    @Autowired
    private LimitUtils limitUtils;
    @Autowired
    private RedisKeyUtils redisKeyUtils;
    @Autowired
    private AiUserHeartbeatRelationDao aiUserHeartbeatRelationDao;
    @Autowired
    private CommonMessageService commonMessageService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private PayClient payClient;

    /**
     * 获取用户与AI的心动关系
     *
     * @param userId
     * @param aiId
     * @return
     */
    @Override
    public AiUserHeartbeatRelation getHeartbeatRelation(Long userId, Long aiId) {
        return getOne(Wrappers.<AiUserHeartbeatRelation>lambdaQuery()
                .eq(AiUserHeartbeatRelation::getUserId, userId)
                .eq(AiUserHeartbeatRelation::getAiId, aiId)
                .last("limit 1"));
    }

    @Override
    public void initAiUserHeartbeatRelation(Long userId, Long aiId) {
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, aiId);
        if (aiUserHeartbeatRelation == null) {
            //保存记录
            aiUserHeartbeatRelation = new AiUserHeartbeatRelation();
            aiUserHeartbeatRelation.setUserId(userId);
            aiUserHeartbeatRelation.setAiId(aiId);
            aiUserHeartbeatRelation.setCreateTime(LocalDateTime.now());
            aiUserHeartbeatRelation.setEditTime(LocalDateTime.now());
            save(aiUserHeartbeatRelation);
        }
    }

    @Override
    public AiUserHeartbeatRelationOutput getAiUserHeartbeatRelation(Long userId, Long aiId) {
        //心动关系
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, aiId);
        AiUserHeartbeatRelationOutput output = new AiUserHeartbeatRelationOutput();
        if (aiUserHeartbeatRelation != null) {
            output = BeanConver.copeBean(aiUserHeartbeatRelation, AiUserHeartbeatRelationOutput.class);
            HeartbeatLevelEnum heartbeatLevel = aiUserHeartbeatRelation.getHeartbeatLevel();
            output.setHeartbeatLevelNum(0);
            if (heartbeatLevel != null) {
                output.setHeartbeatLevelNum(heartbeatLevel.getNum());

//                //心动等级名称
//                HeartbeatLevelDict heartbeatLevelDict = heartbeatLevelDictService.getHeartbeatLevelDictByLevel(heartbeatLevel);
//                output.setHeartbeatLevelName(heartbeatLevelDict.getName());
                //郭老师说 给等级描述，不给上面的东西
                output.setHeartbeatLevelName(heartbeatLevel.getRelationStage());
            }
            //计算相识天数
            output.setDayCount(aiUserHeartbeatRelation.getDayCount());
            //
        }
        //心动值单价
        output.setPrice(HEARTBEAT_VAL_PRICE);
        //用户基础信息
        BaseUserInfoOutput baseUserInfoOutput = userService.baseUserInfo(userId);
        //Ai基础信息
        AiUser aiUser = aiUserSearchService.getAiUserByAiId(aiId);
        output.setUserHeadImg(baseUserInfoOutput != null ? baseUserInfoOutput.getHeadImage() : null);
        output.setAiHeadImg(aiUser != null ? aiUser.getHeadImg() : null);
        return output;
    }

    @Override
    public HeartbeatLevelOutput getAiUserHeartbeatLevel(Long userId, Long aiId) {
        HeartbeatLevelOutput output = new HeartbeatLevelOutput();
        //心动关系
        AiUserHeartbeatRelationOutput aiUserHeartbeatRelation = getAiUserHeartbeatRelation(userId, aiId);
        output.setAiUserHeartbeatRelation(aiUserHeartbeatRelation);
        //心动等级字典列表
        List<HeartbeatLevelDictOutput> heartbeatLevelDictOutputList = heartbeatLevelDictService.getHearbeatLevelDictList(aiUserHeartbeatRelation.getHeartbeatLevel());
        output.setHeartbeatLeveLDictList(heartbeatLevelDictOutputList);
        return output;
    }

    @Override
    public HeartbeatLevelEnum getHeartbeatLevel(Long userId, Long aiId) {
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, aiId);
        return aiUserHeartbeatRelation != null ? aiUserHeartbeatRelation.getHeartbeatLevel() : null;
    }

    @Override
    public Boolean relationCheck(Long userId, Long aiId) {
        int count = count(Wrappers.<AiUserHeartbeatRelation>lambdaQuery()
                .eq(AiUserHeartbeatRelation::getUserId, userId)
                .eq(AiUserHeartbeatRelation::getAiId, aiId)
                .last("limit 1"));
        return count > 0;
    }

    @Override
    public void calcAiUserHeartbeatLevel(CalcHeartbeatLevelPayload payload) {
        Long userId = payload.getUserId();
        Long aiId = payload.getAiId();
        BigDecimal calcHeartbeatVal = payload.getHeartbeatVal();
        CalcHeartbeatLevelPayload.Type type = payload.getType();
        if (userId == null || aiId == null || calcHeartbeatVal == null) {
            return;
        }
        //心动关系获取，初始化
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, aiId);
        if (aiUserHeartbeatRelation == null) {
            aiUserHeartbeatRelation = new AiUserHeartbeatRelation();
            aiUserHeartbeatRelation.setUserId(userId);
            aiUserHeartbeatRelation.setAiId(aiId);
            aiUserHeartbeatRelation.setHeartbeatVal(new BigDecimal(0));
            aiUserHeartbeatRelation.setCreateTime(LocalDateTime.now());
            aiUserHeartbeatRelation.setEditTime(LocalDateTime.now());
            //首次聊天时间
            aiUserHeartbeatRelation.setFirstChatTime(LocalDateTime.now());
            save(aiUserHeartbeatRelation);
            //发送ai会话人数统计
            commonSendMqService.aiUserStatMq(aiId, AiUserStatPayload.Type.FIRST_CHAT, null);
        }
        //聊天类型，发送AI聊天数统计MQ
        if (CalcHeartbeatLevelPayload.Type.isChatType(type)) {
            //发送ai聊天数统计
            commonSendMqService.aiUserStatMq(aiId, AiUserStatPayload.Type.CHAT, null);
        }
        //零值不处理
        if (calcHeartbeatVal.equals(BigDecimal.ZERO)) {
            return;
        }
        //心动值
        BigDecimal subtractHeartbeatVal = aiUserHeartbeatRelation.getSubtractHeartbeatVal() != null ? aiUserHeartbeatRelation.getSubtractHeartbeatVal() : BigDecimal.ZERO;
        //24小时未聊天扣减心动值
        if (CalcHeartbeatLevelPayload.Type.HOURS_WITHOUT_CHAT.equals(type)) {
            //再次判断一下最后聊天时间，如果在24小时内，则不处理
            if (aiUserHeartbeatRelation.getLastChatTime() != null && aiUserHeartbeatRelation.getLastChatTime().plusHours(24).isAfter(LocalDateTime.now())) {
                return;
            }
            //扣减的心动值要加
            subtractHeartbeatVal = subtractHeartbeatVal.add(calcHeartbeatVal);
            //心动值要减
            calcHeartbeatVal = calcHeartbeatVal.multiply(new BigDecimal("-1"));
        }
        BigDecimal oldHeartbeatVal = aiUserHeartbeatRelation.getHeartbeatVal();
        BigDecimal heartbeatVal = aiUserHeartbeatRelation.getHeartbeatVal().add(calcHeartbeatVal);
        //如果小于0了，则设置为0
        if (heartbeatVal.compareTo(new BigDecimal("0")) < 0) {
            heartbeatVal = new BigDecimal("0");
        }
        //根据心动值获取心动等级
        HeartbeatLevelDict heartbeatLevelDict = heartbeatLevelDictService.getHeartbeatLevelByVal(heartbeatVal);
        HeartbeatLevelEnum heartbeatLevelEnum = heartbeatLevelDict != null ? heartbeatLevelDict.getCode() : null;
        //原先等级
        HeartbeatLevelEnum oldHeartbeatLevelEnum = aiUserHeartbeatRelation.getHeartbeatLevel();
        HeartbeatLevelDict oldHeartbeatLevelDict = heartbeatLevelDictService.getHeartbeatLevelDictByLevel(oldHeartbeatLevelEnum);
        //如果降级并且没有等级了，默认成1级
        if (heartbeatLevelEnum == null && HeartbeatLevelEnum.isDowngrade(oldHeartbeatLevelEnum, heartbeatLevelEnum)) {
            heartbeatLevelEnum = HeartbeatLevelEnum.LEVEL_1;
        }
        //更新数据库
        update(Wrappers.<AiUserHeartbeatRelation>lambdaUpdate()
                .set(AiUserHeartbeatRelation::getHeartbeatLevel, heartbeatLevelEnum)
                .set(AiUserHeartbeatRelation::getHeartbeatVal, heartbeatVal)
                //扣减的心动值
                .set(CalcHeartbeatLevelPayload.Type.HOURS_WITHOUT_CHAT.equals(type), AiUserHeartbeatRelation::getSubtractHeartbeatVal, subtractHeartbeatVal)
                .set(AiUserHeartbeatRelation::getEditTime, LocalDateTime.now())
                //聊天类型才更新最后一次聊天时间
                .set(CalcHeartbeatLevelPayload.Type.isChatType(type), AiUserHeartbeatRelation::getLastChatTime, LocalDateTime.now())
                //24小时未聊天扣减心动值，才更新最后一次扣减心动值时间
                .set(CalcHeartbeatLevelPayload.Type.HOURS_WITHOUT_CHAT.equals(type), AiUserHeartbeatRelation::getLastSubtractTime, LocalDateTime.now())
                .eq(AiUserHeartbeatRelation::getId, aiUserHeartbeatRelation.getId())
        );
        //等级升了，发送IM通知
        Boolean isSendImMessage = false;
        String content = "";
        Map<String, Object> extra = new HashMap<>();
        if (HeartbeatLevelEnum.isUpgrade(oldHeartbeatLevelEnum, heartbeatLevelEnum)) {
            isSendImMessage = true;
            content = String.format(ImMessageTypeEnum.HEARTBEAT_LEVEL_UP.getContent(), heartbeatLevelDict.getName());
            extra.put("title", content);

            extra.put("type", ImMessageTypeEnum.HEARTBEAT_LEVEL_UP.name());
        }
        //等级降了，发送IM通知
        if (HeartbeatLevelEnum.isDowngrade(oldHeartbeatLevelEnum, heartbeatLevelEnum)) {
            isSendImMessage = true;
            content = String.format(ImMessageTypeEnum.HEARTBEAT_LEVEL_DOWN.getContent(), oldHeartbeatLevelDict.getName());
            extra.put("title", content);
            extra.put("type", ImMessageTypeEnum.HEARTBEAT_LEVEL_DOWN.name());
            //降级发送系统通知 发送时机 每个角色第一次降级时发送
            if (aiUserHeartbeatRelation.getIsFirstDowngrade() != null && aiUserHeartbeatRelation.getIsFirstDowngrade()) {
                //发送降级通知
                commonMessageService.aiHeartbeatLevelDowngradeSendMessage(userId, aiId, heartbeatLevelEnum != null ? heartbeatLevelEnum.getLevelName() : HeartbeatLevelEnum.LEVEL_1.getLevelName());
                //更新数据库为不是第一次降级
                update(Wrappers.<AiUserHeartbeatRelation>lambdaUpdate()
                        .set(AiUserHeartbeatRelation::getIsFirstDowngrade, false)
                        .eq(AiUserHeartbeatRelation::getId, aiUserHeartbeatRelation.getId())
                );
            }
        }
        if (isSendImMessage) {
            extra.put("heartbeatLevel", heartbeatLevelEnum);
            extra.put("heartbeatLevelNum", heartbeatLevelEnum != null ? heartbeatLevelEnum.getNum() : null);
            extra.put("heartbeatVal", heartbeatVal);
            extra.put("heartbeatLevelName", heartbeatLevelDict != null ? heartbeatLevelDict.getName() : null);
            SendAiCustomerMessageInput sendAiCustomerMessageInput = SendAiCustomerMessageInput.builder()
                    .fromUserId(aiId)
                    .toUserId(userId)
                    .content(content)
                    .attachment(JSON.toJSONString(extra))
                    .build();
            imMessageClient.sendAiToUserCustomerMessage(sendAiCustomerMessageInput);

            //直接删除 response 的缓存，通过聊天来进行自动构建更新等级的变更
            String redisKey = redisKeyUtils.chatResponseIdCacheKey(payload.getUserId(), payload.getAiId());
            log.info("===> del chatResponseIdCacheKey {}, {}, {}, {}, {}", payload.getUserId(), payload.getAiId(), oldHeartbeatLevelEnum, heartbeatLevelEnum, redisKey);
            stringRedisTemplate.delete(redisKey);
            //写入redis清理缓存任务 缓存3天
            stringRedisTemplate.opsForValue().set(redisKeyUtils.chatResponseIdClearTaskKey(payload.getUserId(), payload.getAiId()), "1", 3, TimeUnit.DAYS);
            //写入关系等级缓存
            stringRedisTemplate.opsForValue().set(redisKeyUtils.aiUserHeartbeatLevelCacheKey(payload.getUserId(), aiId), heartbeatLevelEnum.name(), 3650, TimeUnit.DAYS);
        }
        //更新IM的关系标签
        imUpdateConversation(aiId, userId, heartbeatVal, heartbeatLevelEnum == null ? oldHeartbeatLevelEnum : heartbeatLevelEnum, aiUserHeartbeatRelation == null ? true : aiUserHeartbeatRelation.getIsShow());
        //心动分计算 每10分钟达到10次聊天频次就计算一次
        calcHeartbeatScoreMq(userId, aiId);
        //计算心动分值榜单
        commonSendMqService.calcHeartbeatRankMq(aiId, userId, oldHeartbeatVal, heartbeatVal);
    }

    /**
     * 发送MQ计算心动分
     */
    private void calcHeartbeatScoreMq(Long userId, Long aiId) {
        String redisKey = redisKeyUtils.calcHeartbeatScoreLimitKey(userId, aiId);
        boolean b = limitUtils.defaultLimitCheckByKey(redisKey, 10, 10 * 60);
        if (b) {
            //发送MQ计算心动分
            commonSendMqService.calcHeartbeatScoreMq(userId, aiId);
            //删除redis
            stringRedisTemplate.delete(redisKey);
        }
    }

    /**
     * 更新IM会话关系标签
     *
     * @param aiId
     * @param userId
     * @param heartbeatVal
     * @param heartbeatLevelEnum
     * @param isShow
     */
    private void imUpdateConversation(Long aiId, Long userId, BigDecimal heartbeatVal, HeartbeatLevelEnum heartbeatLevelEnum, Boolean isShow) {
        //更新IM的关系标签
        UpdateConversationInput updateConversationInput = UpdateConversationInput.builder()
                .fromUserId(userId)
                .toUserId(aiId)
                .extension(JSONObject.toJSONString(ConversationExtensionInput.builder()
                        .heartbeatVal(heartbeatVal)
                        .heartbeatLevel(heartbeatLevelEnum == null ? null : heartbeatLevelEnum.name())
                        .isShow(isShow)
                        .build()))
                .build();
        imConversationClient.updateConversation(updateConversationInput);
    }


    @Override
    public void buyHeartbeatVal(Long userId, BuyHeartbeatValInput input) {
        Long aiId = input.getAiId();
        //用户与AI关系
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, aiId);
        if (aiUserHeartbeatRelation == null) {
            return;
        }
        //购买的心动值数量
        BigDecimal heartbeatVal = aiUserHeartbeatRelation.getSubtractHeartbeatVal();
        //总金额
        BigDecimal totalAmount = heartbeatVal.multiply(new BigDecimal(HEARTBEAT_VAL_PRICE / 100));
        if (totalAmount.compareTo(new BigDecimal("1")) < 0) {
            totalAmount = totalAmount.setScale(0, RoundingMode.HALF_UP);
        } else {
            totalAmount = totalAmount.setScale(0, RoundingMode.HALF_DOWN);
        }
        //下单，从用户帐户中扣款
        String orderNo = KeyGenerator.instance().generatorUniqueKey("");
        BalanceCheckoutInput balanceCheckoutInput = BalanceCheckoutInput.builder()
                .platform("Balance")
                .outTradeNo(orderNo)
                .bizType(BizType.HEARTBEAT_PURCHASE)
                .name(BizType.HEARTBEAT_PURCHASE.getDesc())
                //付款人
                .srcAccountId(userId)
                //收款人
                .desAccountId(-1L)
                //礼物总金额
                .productAmount(totalAmount.multiply(new BigDecimal(100L)).longValue())
                //折扣金额
                .promoAmount(0L)
                .build();
        payClient.checkoutToB(balanceCheckoutInput);
        //生成购买记录
        BuyHeartbeatValueRecord buyHeartbeatValueRecord = BuyHeartbeatValueRecord.builder()
                .userId(userId).aiId(aiId)
                .price(new BigDecimal(HEARTBEAT_VAL_PRICE)).totalAmount(totalAmount)
                .heartbeatVal(heartbeatVal)
                .orderNo(orderNo)
                .createTime(LocalDateTime.now())
                .editTime(LocalDateTime.now())
                .build();
        buyHeartbeatValueRecordService.addBuyHeartbeatValueRecord(buyHeartbeatValueRecord);
        //已扣减的心动值减去购买数量
        update(Wrappers.<AiUserHeartbeatRelation>lambdaUpdate()
                .set(AiUserHeartbeatRelation::getSubtractHeartbeatVal, aiUserHeartbeatRelation.getSubtractHeartbeatVal().subtract(heartbeatVal))
                .eq(AiUserHeartbeatRelation::getId, aiUserHeartbeatRelation.getId())
        );
        //发送MQ计算心动等级
        commonSendMqService.calHeartbeatLevelSendMq(CalcHeartbeatLevelPayload.builder()
                .userId(userId)
                .aiId(aiId)
                .heartbeatVal(heartbeatVal)
                .type(CalcHeartbeatLevelPayload.Type.BUY_HEARTBEAT_VAL)
                .build());
    }

    @Override
    public void heartbeatRelationSwitch(Long userId, HeartbeatRelationSwitchInput input) {
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, input.getAiId());
        if (aiUserHeartbeatRelation != null) {
            //更新开关
            update(Wrappers.<AiUserHeartbeatRelation>lambdaUpdate()
                    .set(AiUserHeartbeatRelation::getIsShow, input.getIsShow())
                    .eq(AiUserHeartbeatRelation::getId, aiUserHeartbeatRelation.getId())
            );
            //更新IM会话关系标签
            imUpdateConversation(input.getAiId(), userId, aiUserHeartbeatRelation.getHeartbeatVal(), aiUserHeartbeatRelation.getHeartbeatLevel(), input.getIsShow());
        }
    }

    @Override
    public void calcAiUserHeartbeatScore(Long userId, Long aiId) {
        AiUserHeartbeatRelation aiUserHeartbeatRelation = getHeartbeatRelation(userId, aiId);
        if (aiUserHeartbeatRelation == null) {
            return;
        }
        //判断是否达到初识等级,未达到，直接返回
        HeartbeatLevelEnum heartbeatLevel = aiUserHeartbeatRelation.getHeartbeatLevel();
        if (heartbeatLevel == null) {
            return;
        }
        //达到初识关系以及以上的心动值就可以用来与和这个虚拟角色对话过切达到初识关系及以上的其他对话者进行排名，排名/参与排名的所有用户*100%，保留两位小数就是百分比
        //获取最近90天当前用户与AI的心动值排名
        Integer userRank = aiUserHeartbeatRelationDao.getUserHeartbeatRank(userId, aiId);
        //获取最近90天与该AI关系达到初识等级以上的人数
        Integer totalUserCount = aiUserHeartbeatRelationDao.getUserHeartbeatCount(aiId);
        //心动分计算逻辑
        BigDecimal heartbeatScore = new BigDecimal("0.99");
        if (userRank != null && totalUserCount != null && totalUserCount > 1) {
            heartbeatScore = new BigDecimal(1).subtract(new BigDecimal(userRank).divide(new BigDecimal(totalUserCount), 2, RoundingMode.HALF_UP));
        }
        //更新到数据库
        update(Wrappers.<AiUserHeartbeatRelation>lambdaUpdate()
                .set(AiUserHeartbeatRelation::getHeartbeatScore, heartbeatScore)
                .eq(AiUserHeartbeatRelation::getId, aiUserHeartbeatRelation.getId())
        );
    }

    @Override
    public void subtractHeartbeatVal(Long userId) {
        //查询该用户下所有的AI关系
        List<AiUserHeartbeatRelation> list = list(Wrappers.<AiUserHeartbeatRelation>lambdaQuery()
                .eq(AiUserHeartbeatRelation::getUserId, userId)
                .eq(AiUserHeartbeatRelation::getIsShow, true)
        );
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(aiUserHeartbeatRelation -> {
                //最后一次聊天时间
                LocalDateTime lastChatTime = aiUserHeartbeatRelation.getLastChatTime();
                //最后一次扣减心动值时间
                LocalDateTime lastSubtractTime = aiUserHeartbeatRelation.getLastSubtractTime();
                //看以哪个时间来计算
                LocalDateTime calcTime = lastChatTime;
                if (lastSubtractTime != null) {
                    calcTime = lastChatTime.isBefore(lastSubtractTime) ? lastSubtractTime : lastChatTime;
                }
                //判断是否已超过24小时未聊天
                if (calcTime.plusHours(24).isBefore(LocalDateTime.now())) {
                    //已超过24小时未聊天，根据不同心动等级扣除不一样的心动值
                    HeartbeatLevelEnum heartbeatLevelEnum = aiUserHeartbeatRelation.getHeartbeatLevel();
                    //对应等级需要扣除的心动值
                    BigDecimal subtractHeartbeatVal = heartbeatLevelEnum.getSubtractHeartbeatVal();
                    //计算超过多少天没有聊天了
                    long hours = Duration.between(calcTime, LocalDateTime.now()).toHours();
                    long dayCount = hours / 24; // 按24小时算1天
                    //总的需要扣除的心动值
                    BigDecimal totalSubtractHeartbeatVal = subtractHeartbeatVal.multiply(new BigDecimal(dayCount));
                    //发送到心动等级计算MQ
                    commonSendMqService.calHeartbeatLevelSendMq(CalcHeartbeatLevelPayload.builder()
                            .userId(userId)
                            .aiId(aiUserHeartbeatRelation.getAiId())
                            .heartbeatVal(totalSubtractHeartbeatVal)
                            .type(CalcHeartbeatLevelPayload.Type.HOURS_WITHOUT_CHAT)
                            .build());
                }
            });
        }
    }

    @Override
    public void withoutChatSubtractHeartbeatVal(Long userId) {
        //24小时未聊天发送MQ到扣减心动值
//        commonSendMqService.subtractHeartbeatValMq(userId);
    }

    @Override
    public Page<HeartbeatRelationListOutput> heartbeatRelationList(Long userId, HeartbeatRelationListInput input) {
        input.setUserId(userId);
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<AiUserHeartbeatRelation> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(input.getPage().getPn(), input.getPage().getPs());
        IPage<AiUserHeartbeatRelation> pageResult = aiUserHeartbeatRelationDao.heartbeatRelationListPage(page, input);
        List<AiUserHeartbeatRelation> records = pageResult.getRecords();
        List<Long> aiIdList = records.stream().map(AiUserHeartbeatRelation::getAiId).collect(Collectors.toList());
        //Ai基础信息Map
        Map<Long, AiUserBaseOutput> aiUserMap = aiUserSearchService.mapByAiIdList(aiIdList);
        return PageConverter.convert(pageResult, aiUserHeartbeatRelation -> {
            AiUserBaseOutput aiUserBaseOutput = aiUserMap.get(aiUserHeartbeatRelation.getAiId());
            //基础信息
            HeartbeatRelationListOutput output = BeanConver.copeBean(aiUserBaseOutput, HeartbeatRelationListOutput.class);
            output.setAiId(aiUserHeartbeatRelation.getAiId());
            //业务信息
            output.setHeartbeatLevel(aiUserHeartbeatRelation.getHeartbeatLevel());
            output.setHeartbeatVal(aiUserHeartbeatRelation.getHeartbeatVal());
            output.setHeartbeatLevelNum(aiUserHeartbeatRelation.getHeartbeatLevel().getNum());
            output.setIsShow(aiUserHeartbeatRelation.getIsShow() == null ? true : aiUserHeartbeatRelation.getIsShow());
            return output;
        });
    }

    @Override
    public void hours24NoChatSubtractHeartbeatValJob() {
        //24小时后
        LocalDateTime calcTime = LocalDateTime.now().minusHours(24);
        //查询有心动值的，且最后扣减时间小于该时间段，且最后聊天时间小于该时间段的关系,每次取1000条数据
        List<AiUserHeartbeatRelation> list = aiUserHeartbeatRelationDao.hours24NoChatRelationList(calcTime);
        //发送扣减心动值MQ处理
        for (AiUserHeartbeatRelation aiUserHeartbeatRelation : list) {
            Long userId = aiUserHeartbeatRelation.getUserId();
            Long aiId = aiUserHeartbeatRelation.getAiId();
            //已超过24小时未聊天，根据不同心动等级扣除不一样的心动值
            HeartbeatLevelEnum heartbeatLevelEnum = aiUserHeartbeatRelation.getHeartbeatLevel();
            if (heartbeatLevelEnum == null) {
                continue;
            }
            //对应等级需要扣除的心动值
            BigDecimal subtractHeartbeatVal = heartbeatLevelEnum.getSubtractHeartbeatVal();
            //发送到心动等级计算MQ
            commonSendMqService.calHeartbeatLevelSendMq(CalcHeartbeatLevelPayload.builder()
                    .userId(userId)
                    .aiId(aiId)
                    .heartbeatVal(subtractHeartbeatVal)
                    .type(CalcHeartbeatLevelPayload.Type.HOURS_WITHOUT_CHAT)
                    .build());
        }
    }

    @Override
    public Map<Long, BigDecimal> queryAIHeartbeatVal(Long currentUserId, List<Long> aiIds) {
        if (currentUserId == null || aiIds == null || aiIds.isEmpty()) {
            return new HashMap<>(0);
        }
        List<AiUserHeartbeatRelation> list = list(Wrappers.<AiUserHeartbeatRelation>lambdaQuery()
                .select(AiUserHeartbeatRelation::getAiId, AiUserHeartbeatRelation::getHeartbeatVal)
                .eq(AiUserHeartbeatRelation::getUserId, currentUserId)
                .in(AiUserHeartbeatRelation::getAiId, aiIds));
        Map<Long, BigDecimal> aiHeartbeatValMap = new HashMap<>(aiIds.size());
        for (AiUserHeartbeatRelation aiUserHeartbeatRelation : list) {
            aiHeartbeatValMap.put(aiUserHeartbeatRelation.getAiId(), aiUserHeartbeatRelation.getHeartbeatVal() == null ? BigDecimal.ZERO : aiUserHeartbeatRelation.getHeartbeatVal());
        }
        return aiHeartbeatValMap;
    }
}