package com.sonic.frog.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sonic.frog.dao.LikedDao;
import com.sonic.frog.dao.UserAiMeetDao;
import com.sonic.frog.domain.bo.RandomMeetRateBo;
import com.sonic.frog.domain.entity.*;
import com.sonic.frog.domain.output.MeetSdOutput;
import com.sonic.frog.event.inner.payload.AiUserStatPayload;
import com.sonic.frog.service.*;
import com.sonic.frog.utils.LimitUtils;
import com.sonic.frog.utils.RedisKeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户和AI相互喜欢记录表
 * </p>
 *
 * @author mzc
 * @since 2024-11-28
 */
@Service
@Slf4j
public class UserAiMeetServiceImpl extends ServiceImpl<UserAiMeetDao, UserAiMeet> implements UserAiMeetService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisKeyUtils redisKeyUtils;
    @Autowired
    private AiUserService aiUserService;
    @Autowired
    private LimitUtils limitUtils;
    @Autowired
    private CommonSendMqService commonSendMqService;
    @Autowired
    private LikedDao likedDao;

    /**
     * 默认次数列表
     */
    List<Integer> DEFAULT_INDEX_LIST = Lists.newArrayList(
            31, 62, 93, 114, 145, 176, 207, 238, 269, 300,
            331, 362, 393, 424, 455, 486, 517, 548, 579, 610
    );
    @Autowired
    private AiUserStatService aiUserStatService;
    @Autowired
    private AiUserAlbumService aiUserAlbumService;

    @Override
    public MeetSdOutput meetSd(Long userId, Long aiId, boolean lk) {
        MeetSdOutput output = new MeetSdOutput();
        //先增加滑动次数
        int sdCount = limitUtils.defaultLimitCheckReturnCount(redisKeyUtils.meetSdCount(userId), 2 * 60 * 60);
        //次数不足10次或已经大于70次了，或者不为喜欢的卡片，则直接快速返回掉
        if(sdCount < 10 || sdCount > 70 || !lk) {
            output.setBd(false);
        } else {
            output.setBd(getLikeMeetBl(userId, aiId, sdCount));
        }
        //计算是否触发秘密爱慕者
        if(DEFAULT_INDEX_LIST.contains(sdCount)) {
            output.setRc(true);
        }
        if(userId != null && sdCount < 500) {
            //点赞或取消点赞
            likedDao.likeOrCancel(Liked.builder()
                    .bizId(aiId)
                    .bizType(Liked.BizType.AI)
                    .aiId(aiId)
                    .likedUserId(userId)
                    .likedStatus(lk? Liked.LikedStatus.LIKED : Liked.LikedStatus.CANCELED).build());
            //如果是喜欢或者不喜欢的AI的话，需要发送MQ消息，异步计算喜欢总数
            commonSendMqService.aiUserStatMq(aiId, lk ? AiUserStatPayload.Type.LIKED : AiUserStatPayload.Type.CANCEL_LIKED, null);
        }
        return output;
    }

    /**
     * 获取当前喜欢是否匹配上了
     * @param userId
     * @param aiId
     * @param sdCount
     * @return
     */
    private boolean getLikeMeetBl(Long userId, Long aiId, int sdCount) {
        RandomMeetRateBo bo = getRateBo(userId);
        if(bo == null) {
            return false;
        }
        if(sdCount >= 11 && sdCount <= 20 && bo.getBl1120()) {
            //写入待消费数据、10秒钟过期，并修改当前的状态
            bo.setBl1120(false);
            updateRateBoAndSetUploadAccess(userId, aiId, bo);
            return true;
        }
        if(sdCount >= 31 && sdCount <= 40 && (bo.getBl1120() || bo.getBl3140())) {
            //写入待消费数据、10秒钟过期，并修改当前的状态
            bo.setBl1120(false);
            bo.setBl3140(false);
            updateRateBoAndSetUploadAccess(userId, aiId, bo);
            return true;
        }
        if(sdCount >= 41 && sdCount <= 50 && (bo.getBl1120() || bo.getBl4150())) {
            //写入待消费数据、10秒钟过期，并修改当前的状态
            bo.setBl1120(false);
            bo.setBl3140(false);
            bo.setBl4150(false);
            updateRateBoAndSetUploadAccess(userId, aiId, bo);
            return true;
        }
        if(sdCount >= 51 && sdCount <= 60 && (bo.getBl1120() || bo.getBl5160())) {
            //写入待消费数据、10秒钟过期，并修改当前的状态
            bo.setBl1120(false);
            bo.setBl3140(false);
            bo.setBl4150(false);
            bo.setBl5160(false);
            updateRateBoAndSetUploadAccess(userId, aiId, bo);
            return true;
        }
        if(sdCount >= 61 && sdCount <= 70 && (bo.getBl1120() || bo.getBl6170())) {
            //写入待消费数据、10秒钟过期，并修改当前的状态
            bo.setBl1120(false);
            bo.setBl3140(false);
            bo.setBl4150(false);
            bo.setBl5160(false);
            bo.setBl6170(false);
            updateRateBoAndSetUploadAccess(userId, aiId, bo);
            return true;
        }
        return false;
    }

    /**
     * 获取随机匹配的概率
     * @param userId
     * @return
     */
    private RandomMeetRateBo getRateBo(Long userId) {
        //获取滑动的
        String meetRateStr = stringRedisTemplate.opsForValue().get(redisKeyUtils.meetRateBoKey(userId));
        if(StringUtils.isEmpty(meetRateStr)) {
            return null;
        }
        log.info("===> getRateBo : {}", meetRateStr);
        return JSONObject.parseObject(meetRateStr, RandomMeetRateBo.class);
    }

    /**
     * 修改值，并设置上报meet权限
     * @param userId
     * @param bo
     */
    private void updateRateBoAndSetUploadAccess(Long userId, Long aiId, RandomMeetRateBo bo) {
        //写入redis，赋予上传权限
        stringRedisTemplate.opsForValue().set(redisKeyUtils.uploadMeet(userId, aiId), "1", 60, TimeUnit.SECONDS);
        //获取过期时间
        long expTime = stringRedisTemplate.getExpire(redisKeyUtils.meetRateBoKey(userId));
        log.debug("===> updateRateBoAndSetUploadAccess expTime : {}", expTime);
        if(expTime <= 0) {
            //如果是永不过期，那么删掉数据
            if(expTime == -1) {
                stringRedisTemplate.delete(redisKeyUtils.meetRateBoKey(userId));
            }
            return;
        }
        String redisValue = JSONObject.toJSONString(bo);
        log.info("===> updateRateBoAndSetUploadAccess redisValue : {}", redisValue);
        stringRedisTemplate.opsForValue().set(redisKeyUtils.meetRateBoKey(userId), redisValue, expTime, TimeUnit.SECONDS);
    }


    @Override
    public boolean meetBd(Long userId, Long aiId) {
        boolean hasKey = stringRedisTemplate.hasKey(redisKeyUtils.uploadMeet(userId, aiId));
        //校验用户是否有上报meet卡片的权限，没有的话直接快速返回掉，不进行任何处理
        if(!hasKey) {
            return false;
        }
        //判断AI是否存在 且 不能是自己的AI，是否公开
        int count = aiUserService.count(Wrappers.<AiUser>lambdaQuery()
                .eq(AiUser::getAiId, aiId)
                .ne(AiUser::getUserId, userId)
                .eq(AiUser::getIsDelete, false)
                .eq(AiUser::getPermission, 1));
        if(count != 1) {
            return false;
        }
        //执行添加操作是否成功
        boolean add = addMeet(userId, aiId);
        if(add) {
            //TODO 绑定成功，发送IM消息？？？

        }
        return add;
    }

    @Override
    public Long meetRc(Long userId) {
        //频率限制，2小时内同一个用户最多调用20次，超过20次则直接不返回任何数据
        int limit = limitUtils.defaultLimitCheckReturnCount(redisKeyUtils.meetRcLimit(userId), 2 * 60 * 60);
        if(limit > 20) {
            return null;
        }
        //查询待推荐数据：从被喜欢次数排名前100的随机给出一个
        List<Long> exAiIds = list(Wrappers.<UserAiMeet>lambdaQuery()
                .select(UserAiMeet::getAiId)
                .eq(UserAiMeet::getUserId, userId)).stream().map(UserAiMeet::getAiId)
                .collect(Collectors.toList());
        //排除掉已喜欢的数据
        List<Long> aiIdList = aiUserStatService.list(Wrappers.<AiUserStat>lambdaQuery()
                        .select(AiUserStat::getAiId)
                        .notIn(CollectionUtils.isNotEmpty(exAiIds), AiUserStat::getAiId, exAiIds)
                        .orderByDesc(AiUserStat::getLikedNum).last("LIMIT 50"))
                .stream().map(AiUserStat::getAiId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(aiIdList)) {
            return null;
        }
        //查询默认图片ID出来
        List<AiUserAlbum> aiUserAlbumList = aiUserAlbumService.list(Wrappers.<AiUserAlbum>lambdaQuery()
                        .select(AiUserAlbum::getId)
                .in(AiUserAlbum::getAiId, aiIdList)
                .eq(AiUserAlbum::getIsDefault, true)
                .eq(AiUserAlbum::getIsDelete, false));
        if(CollectionUtils.isEmpty(aiUserAlbumList)) {
            return null;
        }
        //随机
        Collections.shuffle(aiUserAlbumList);
        //获取一条数据
        AiUserAlbum aiUserAlbum = aiUserAlbumList.get(0);
        return aiUserAlbum == null ? null : aiUserAlbum.getId();
    }

    @Override
    public boolean addMeet(Long userId, Long aiId) {
        try {
            UserAiMeet userAiMeet = UserAiMeet.builder()
                    .userId(userId)
                    .aiId(aiId)
                    .createTime(LocalDateTime.now())
                    .build();
            save(userAiMeet);
        } catch (Exception e) {
            //吃掉异常，返回失败
            return false;
        }
        return true;
    }

}

