package com.java2nb.novel.service.impl;

import com.java2nb.novel.service.LikeService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.StaticScriptSource;
import org.springframework.stereotype.Service;

import java.util.Collections;

/**
 * @author xiongxiaoyang
 * @date 2025/7/12
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LikeServiceImpl implements LikeService {

    private final StringRedisTemplate redisTemplate;

    private DefaultRedisScript<Long> toggleLikeScript;

    private static final String COMMENT_LIKE_KEY_PREFIX = "like:comment:";
    private static final String COMMENT_REPLY_LIKE_KEY_PREFIX = "like:comment:reply:";
    private static final String COMMENT_UN_LIKE_KEY_PREFIX = "unlike:comment:";
    private static final String COMMENT_REPLY_UN_LIKE_KEY_PREFIX = "unlike:comment:reply:";

    @PostConstruct
    public void init() {
        // Lua 脚本保证原子性操作
        String script = """
                local key = KEYS[1]
                local userId = ARGV[1]
            
                local isLiked = redis.call('SISMEMBER', key, userId)
            
                if isLiked == 1 then
                    redis.call('SREM', key, userId)
                else
                    redis.call('SADD', key, userId)
                end
            
                return redis.call('SCARD', key)
            """;

        toggleLikeScript = new DefaultRedisScript<>();
        toggleLikeScript.setScriptSource(new StaticScriptSource(script));
        toggleLikeScript.setResultType(Long.class);
    }

    public Long toggleCommentLike(Long commentId, Long userId) {
        return executeToggle(COMMENT_LIKE_KEY_PREFIX + commentId, userId);
    }

    @Override
    public Long toggleCommentUnLike(Long commentId, Long userId) {
        return executeToggle(COMMENT_UN_LIKE_KEY_PREFIX + commentId, userId);
    }

    public Long getCommentLikesCount(Long commentId) {
        return redisTemplate.opsForSet().size(COMMENT_LIKE_KEY_PREFIX + commentId);
    }

    @Override
    public Long getCommentUnLikesCount(Long commentId) {
        return redisTemplate.opsForSet().size(COMMENT_UN_LIKE_KEY_PREFIX + commentId);
    }

    public Long toggleReplyLike(Long replyId, Long userId) {
        return executeToggle(COMMENT_REPLY_LIKE_KEY_PREFIX + replyId, userId);
    }

    @Override
    public Long toggleReplyUnLike(Long replyId, Long userId) {
        return executeToggle(COMMENT_REPLY_UN_LIKE_KEY_PREFIX + replyId, userId);
    }

    public Long getReplyLikesCount(Long replyId) {
        return redisTemplate.opsForSet().size(COMMENT_REPLY_LIKE_KEY_PREFIX + replyId);
    }

    @Override
    public Long getReplyUnLikesCount(Long replyId) {
        return redisTemplate.opsForSet().size(COMMENT_REPLY_UN_LIKE_KEY_PREFIX + replyId);
    }

    private Long executeToggle(String key, Long userId) {
        return redisTemplate.execute(toggleLikeScript, Collections.singletonList(key), String.valueOf(userId));
    }
}
