package com.ycwl.basic.repository;

import com.ycwl.basic.model.pc.video.entity.UserVideoViewEntity;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 用户视频查看记录Repository
 * 仅使用Redis存储查看记录
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class UserVideoViewRepository {

    private final RedisTemplate<String, String> redisTemplate;

    private static final String USER_VIDEO_VIEW_CACHE_KEY = "user_video_view:%s:%s";
    private static final String VIEW_RECORD_LOCK_KEY = "view_record_lock:%s:%s";
    private static final int CACHE_EXPIRE_HOURS = 72; // 3天过期
    private static final int LOCK_EXPIRE_SECONDS = 30;

    /**
     * 获取用户视频查看记录
     *
     * @param userId  用户ID
     * @param videoId 视频ID
     * @return 查看记录
     */
    public UserVideoViewEntity getViewRecord(Long userId, Long videoId) {
        String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);

        if (redisTemplate.hasKey(cacheKey)) {
            String cached = redisTemplate.opsForValue().get(cacheKey);
            if (cached != null) {
                return JacksonUtil.parseObject(cached, UserVideoViewEntity.class);
            }
        }

        return null;
    }

    /**
     * 创建查看记录
     *
     * @param userId   用户ID
     * @param videoId  视频ID
     * @param scenicId 景区ID
     * @return 查看记录
     */
    public UserVideoViewEntity createViewRecord(Long userId, Long videoId, Long scenicId) {
        UserVideoViewEntity entity = new UserVideoViewEntity();
        entity.setUserId(userId);
        entity.setVideoId(videoId);
        entity.setScenicId(scenicId);
        entity.setViewCount(1);
        entity.setLastViewTime(new Date());
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());

        String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
        redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(entity),
                CACHE_EXPIRE_HOURS, TimeUnit.HOURS);

        log.debug("创建用户视频查看记录到Redis: userId={}, videoId={}, scenicId={}", userId, videoId, scenicId);
        return entity;
    }

    /**
     * 更新查看次数
     *
     * @param userId    用户ID
     * @param videoId   视频ID
     * @param viewCount 新的查看次数
     * @return 是否更新成功
     */
    public boolean updateViewCount(Long userId, Long videoId, Integer viewCount) {
        UserVideoViewEntity entity = getViewRecord(userId, videoId);
        if (entity != null) {
            entity.setViewCount(viewCount);
            entity.setLastViewTime(new Date());
            entity.setUpdateTime(new Date());

            String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
            redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(entity),
                    CACHE_EXPIRE_HOURS, TimeUnit.HOURS);

            log.debug("更新用户视频查看次数到Redis: userId={}, videoId={}, viewCount={}", userId, videoId, viewCount);
            return true;
        }
        return false;
    }

    /**
     * 增加查看次数（原子操作）
     *
     * @param userId  用户ID
     * @param videoId 视频ID
     * @return 是否更新成功
     */
    public boolean incrementViewCount(Long userId, Long videoId) {
        UserVideoViewEntity entity = getViewRecord(userId, videoId);
        if (entity != null) {
            entity.setViewCount(entity.getViewCount() + 1);
            entity.setLastViewTime(new Date());
            entity.setUpdateTime(new Date());

            String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
            redisTemplate.opsForValue().set(cacheKey, JacksonUtil.toJSONString(entity),
                    CACHE_EXPIRE_HOURS, TimeUnit.HOURS);

            log.debug("增加用户视频查看次数到Redis: userId={}, videoId={}, newCount={}",
                    userId, videoId, entity.getViewCount());
            return true;
        }
        return false;
    }

    /**
     * 使用Redis分布式锁执行查看记录操作
     *
     * @param userId    用户ID
     * @param videoId   视频ID
     * @param operation 操作函数
     * @return 操作结果
     */
    public <T> T executeWithLock(Long userId, Long videoId, java.util.function.Supplier<T> operation) {
        String lockKey = String.format(VIEW_RECORD_LOCK_KEY, userId, videoId);

        try {
            // 尝试获取锁
            Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked",
                    LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);

            if (Boolean.TRUE.equals(lockAcquired)) {
                try {
                    return operation.get();
                } finally {
                    // 释放锁
                    redisTemplate.delete(lockKey);
                }
            } else {
                log.warn("获取查看记录锁失败: userId={}, videoId={}", userId, videoId);
                return null;
            }
        } catch (Exception e) {
            log.error("执行查看记录操作失败: userId={}, videoId={}", userId, videoId, e);
            return null;
        }
    }

    /**
     * 清除缓存
     *
     * @param userId  用户ID
     * @param videoId 视频ID
     */
    public void clearCache(Long userId, Long videoId) {
        String cacheKey = String.format(USER_VIDEO_VIEW_CACHE_KEY, userId, videoId);
        redisTemplate.delete(cacheKey);
    }
}