package cn.reghao.tnb.content.app.vod.service.impl;

import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.tnb.common.web.ServletUtil;
import cn.reghao.tnb.common.web.WebResult;
import cn.reghao.tnb.common.auth.UserContext;
import cn.reghao.tnb.common.db.PageScroll;
import cn.reghao.tnb.content.api.constant.RcmdMode;
import cn.reghao.tnb.content.api.dto.VideoCard;
import cn.reghao.tnb.content.api.dto.VideoPostCard;
import cn.reghao.tnb.content.app.util.redis.ds.RedisList;
import cn.reghao.tnb.content.app.util.redis.ds.RedisOps;
import cn.reghao.tnb.content.app.vod.db.mapper.VideoPostMapper;
import cn.reghao.tnb.content.app.vod.model.po.VideoPost;
import cn.reghao.tnb.content.app.vod.model.query.VideoQuery;
import cn.reghao.tnb.content.app.vod.model.vo.BannerVideoVO;
import cn.reghao.tnb.content.app.vod.service.ContentPermission;
import cn.reghao.tnb.content.app.vod.service.RecommendService;
import cn.reghao.tnb.content.app.vod.service.VideoPostQuery;
import cn.reghao.tnb.content.app.vod.service.rcmd.task.RcmdData;
import cn.reghao.tnb.content.app.vod.service.rcmd.task.RcmdProducer;
import cn.reghao.tnb.content.app.vod.service.rcmd.RedisKeys;
import cn.reghao.tnb.content.app.util.redis.ds.RedisSet;
import cn.reghao.tnb.user.api.iface.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2024-08-07 07:32:32
 */
@Slf4j
@Service
public class RecommendServiceImpl implements RecommendService {
    @DubboReference(check = false, retries = 0, timeout = 3000)
    private UserService userService;

    private final int pageSize = 12;
    private final ContentPermission contentPermission;
    private final VideoPostMapper videoPostMapper;
    private final VideoPostQuery videoPostQuery;
    private final RedisSet redisSet;
    private final RedisList redisList;
    private final RcmdProducer rcmdProducer;
    private RedisOps redisOps;

    public RecommendServiceImpl(ContentPermission contentPermission, VideoPostMapper videoPostMapper,
                                VideoPostQuery videoPostQuery, RedisSet redisSet, RedisList redisList,
                                RcmdProducer rcmdProducer, RedisOps redisOps) {
        this.contentPermission = contentPermission;
        this.videoPostMapper = videoPostMapper;
        this.videoPostQuery = videoPostQuery;
        this.redisSet = redisSet;
        this.redisList = redisList;
        this.rcmdProducer = rcmdProducer;
        this.redisOps = redisOps;
    }

    public List<VideoCard> getRecommendVideos(long userId, String nextId) {
        String itemsKey = RedisKeys.getUserItemKey(userId);
        List<VideoCard> videoCards = new ArrayList<>();
        List<Object> list = redisSet.spop(itemsKey, pageSize);
        for (Object obj : list) {
            if (obj instanceof VideoCard) {
                videoCards.add((VideoCard) obj);
            }
        }

        putRecommendVideos(userId, pageSize*3);
        return videoCards;
    }

    public void putRecommendVideos(long loginUser, int size) {
        String itemsKey = RedisKeys.getUserItemKey(loginUser);
        long len = redisSet.scard(itemsKey);
        if (len > pageSize*100) {
            return;
        }

        try {
            String requestId = ServletUtil.getHeader("x-request-id");
            rcmdProducer.put(new RcmdData(requestId, loginUser, size));
        } catch (Exception e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void resetUserRcmd(long userId) {
        String itemsKey = RedisKeys.getUserItemKey(userId);
        redisSet.spop(itemsKey);
    }

    @Override
    public void dislikeVideo(long userId, String videoId) {
        String dislikeKey = RedisKeys.getUserDislikeKey(userId);
        redisList.add(dislikeKey, videoId);
    }

    public String getSimilarVideos(String videoId) {
        VideoPost videoPost = videoPostMapper.findByVideoId(videoId);
        if (videoPost == null) {
            return WebResult.notFound();
        }

        LocalDateTime publishAt = videoPost.getPublishAt();
        long publishBy = videoPost.getPublishBy();
        List<Integer> scopes = contentPermission.getUserScopes();
        VideoQuery videoQuery = new VideoQuery.Builder().scope(scopes).userId(publishBy).build();
        List<VideoPostCard> list = videoPostMapper.findByNextVideos(videoQuery, publishAt);
        List<VideoCard> list1 = list.stream()
                .map(videoPostCard -> videoPostQuery.getVideoCard(videoPostCard, true))
                .collect(Collectors.toList());
        return WebResult.success(list1);
    }

    /**
     * 视频稿件时间线
     *
     * @param
     * @return
     * @date 2023-08-26 01:08:740
     */
    public PageScroll<VideoCard> getVideoTimeline(long userId, String nextIdStr) {
        List<Long> followings = userService.getFollowingIds(userId);
        followings.add(userId);

        int nextId;
        if (nextIdStr.equals("0")) {
            nextId = 99_999_999;
        } else {
            VideoPost videoPost = videoPostMapper.findByVideoId(nextIdStr);
            if (videoPost == null) {
                return PageScroll.empty();
            }

            nextId = videoPost.getId();
        }

        List<VideoPostCard> list = videoPostMapper.findByUserIds(followings, pageSize, nextId);
        if (list.isEmpty()) {
            return PageScroll.empty();
        }

        List<VideoCard> list1 = list.stream()
                .map(videoPostCard -> videoPostQuery.getVideoCard(videoPostCard, true))
                .collect(Collectors.toList());
        nextIdStr = list.get(list.size()-1).getVideoId();
        return PageScroll.pageList(0, nextIdStr, nextIdStr, list1);
    }

    public List<BannerVideoVO> getBannerVideos() {
        return videoPostQuery.getBannerVideos();
    }

    public Result setRecommendMode(boolean mode) {
        long loginUser = UserContext.getUserId();
        boolean vip = userService.isVip(loginUser);
        if (mode && !vip) {
            return Result.fail("此功能仅对 VIP 用户开放");
        }

        boolean changed;
        if (mode) {
            changed = userService.setRecommendMode(loginUser, RcmdMode.VIP.getValue());
        } else {
            changed = userService.setRecommendMode(loginUser, RcmdMode.USER.getValue());
        }

        if (changed) {
            String itemsKey = RedisKeys.getUserItemKey(loginUser);
            redisOps.del(itemsKey);
        }

        return Result.success();
    }

    public boolean getRecommendMode() {
        long userId1 = UserContext.getUserId();
        int mode = userService.getRecommendMode(userId1);
        return mode == RcmdMode.VIP.getValue();
    }
}
