package com.luojia_channel.common.utils;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class RedisUtil {

    private final RedisTemplate<String, Object> redisTemplate;
    private static final Long DEFAULT_TIMEOUT = 30000L;
    private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;

    /**
     * redis基础操作
     */

    public <T> T get(String key, Class<T> type) {
        Object value = redisTemplate.opsForValue().get(key);
        return value != null ? type.cast(value) : null;
    }

    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
    }

    public void set(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    public void expire(String key, long time, TimeUnit timeUnit) {
        redisTemplate.expire(key, time, timeUnit);
    }

    public void delete(String key) {
        redisTemplate.delete(key);
    }

    public boolean hasKey(String key) {
        Boolean result = redisTemplate.hasKey(key);
        return result != null;
    }

    public Long getExpire(String key, TimeUnit timeUnit){
        return redisTemplate.getExpire(key, timeUnit);
    }

    /**
     * set操作
     */
    private <T> List<T> convertSetToList(Set<Object> set) {
        if(set == null || set.isEmpty()){
            return Collections.emptyList();
        }
        return set.stream().map(obj -> (T) obj).collect(Collectors.toList());
    }

    public void sAdd(String key, Object... values) {
        redisTemplate.opsForSet().add(key, values);
    }

    public void sRemove(String key, Object... values) {
        redisTemplate.opsForSet().remove(key, values);
    }

    public <T> List<T> sGet(String key) {
        Set<Object> members = redisTemplate.opsForSet().members(key);
        return convertSetToList(members);
    }

    public Boolean sIsMember(String key, Object value){
        return redisTemplate.opsForSet().isMember(key, value);
    }

    public <T> List<T> sCommon(String key, String otherKey){
        Set<Object> intersect = redisTemplate.opsForSet().intersect(key, otherKey);
        return convertSetToList(intersect);
    }


    /**
     * zSet操作
     */
    // 带分数的结果包装类
    @Data
    @AllArgsConstructor
    public static class ZSetItem<T> {
        private T value;
        private Double score;
    }
    private <T> List<ZSetItem<T>> convertTuples(Set<ZSetOperations.TypedTuple<Object>> tuples) {
        if(tuples == null || tuples.isEmpty()){
            return Collections.emptyList();
        }
        return tuples.stream()
                .map(tuple -> new ZSetItem<T>(
                        (T) tuple.getValue(),
                        tuple.getScore() != null ? tuple.getScore() : 0.0
                ))
                .collect(Collectors.toList());
    }

    // 添加元素
    public Boolean zAdd(String key, Object value, double score) {
        return redisTemplate.opsForZSet().add(key, value, score);
    }

    public Boolean zAdd(String key, Object value, double score, long timeout, TimeUnit unit) {
        Boolean result = redisTemplate.opsForZSet().add(key, value, score);
        if (Boolean.TRUE.equals(result)) {
            redisTemplate.expire(key, timeout, unit);
        }
        return result;
    }

    // 获取范围
    public <T> List<T> zRange(String key, long start, long end) {
        Set<Object> values = redisTemplate.opsForZSet().range(key, start, end);
        return convertSetToList(values);
    }

    public <T> List<T> zRevRange(String key, long start, long end) {
        Set<Object> values = redisTemplate.opsForZSet().reverseRange(key, start, end);
        return convertSetToList(values);
    }

    // 带分数查询（用于热度计算）
    public <T> List<ZSetItem<T>> zRangeWithScores(String key, long start, long end) {
        Set<ZSetOperations.TypedTuple<Object>> typedTuples = redisTemplate.opsForZSet().rangeWithScores(key, start, end);
        return convertTuples(typedTuples);
    }

    // 增减分数（用于点赞数统计）
    public Double zIncrScore(String key, Object value, double delta) {
        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
    }

    // 删除元素
    public Long zRemove(String key, Object... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }

    // 获取排名（用于热榜）
    public Long zRank(String key, Object value) {
        return redisTemplate.opsForZSet().rank(key, value);
    }

    public Long zRevRank(String key, Object value) {
        return redisTemplate.opsForZSet().reverseRank(key, value);
    }

    // 获取集合大小
    public Long zCard(String key) {
        return redisTemplate.opsForZSet().zCard(key);
    }


}