package com.ruoyi.credit.service;

import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.credit.domain.LoanConsistencyValidation;
import com.ruoyi.credit.domain.ValidationStatistics;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 验证结果缓存管理器
 * 
 * 负责管理贷款一致性验证结果的Redis缓存存储，包括缓存失效、更新机制和预加载功能
 * 
 * @author ruoyi
 */
@Component
public class ValidationCacheManager {

    private static final Logger log = LoggerFactory.getLogger(ValidationCacheManager.class);

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 缓存过期时间（分钟）
     */
    private static final int CACHE_EXPIRE_MINUTES = 5;

    /**
     * 分布式锁超时时间（秒）
     */
    private static final int LOCK_TIMEOUT_SECONDS = 10;

    /**
     * 缓存验证结果
     *
     * @param loanId 贷款ID
     * @param validation 验证结果
     */
    public void cacheValidationResult(Long loanId, LoanConsistencyValidation validation) {
        if (loanId == null || validation == null) {
            log.warn("无法缓存验证结果：loanId或validation为空");
            return;
        }

        try {
            String cacheKey = buildValidationCacheKey(loanId);
            redisCache.setCacheObject(cacheKey, validation, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
            log.debug("已缓存贷款{}的验证结果，状态：{}", loanId, validation.getValidationStatus());
        } catch (Exception e) {
            log.error("缓存验证结果失败，loanId: {}", loanId, e);
        }
    }

    /**
     * 获取缓存的验证结果
     *
     * @param loanId 贷款ID
     * @return 验证结果，如果缓存中不存在则返回null
     */
    public LoanConsistencyValidation getCachedValidationResult(Long loanId) {
        if (loanId == null) {
            return null;
        }

        try {
            String cacheKey = buildValidationCacheKey(loanId);
            LoanConsistencyValidation result = redisCache.getCacheObject(cacheKey);
            if (result != null) {
                log.debug("从缓存获取贷款{}的验证结果，状态：{}", loanId, result.getValidationStatus());
            }
            return result;
        } catch (Exception e) {
            log.error("获取缓存验证结果失败，loanId: {}", loanId, e);
            return null;
        }
    }

    /**
     * 失效指定贷款的缓存
     *
     * @param loanId 贷款ID
     */
    public void invalidateCache(Long loanId) {
        if (loanId == null) {
            return;
        }

        try {
            String cacheKey = buildValidationCacheKey(loanId);
            boolean deleted = redisCache.deleteObject(cacheKey);
            if (deleted) {
                log.debug("已失效贷款{}的验证缓存", loanId);
            }
        } catch (Exception e) {
            log.error("失效验证缓存失败，loanId: {}", loanId, e);
        }
    }

    /**
     * 批量失效缓存
     *
     * @param loanIds 贷款ID列表
     */
    public void invalidateCacheBatch(List<Long> loanIds) {
        if (loanIds == null || loanIds.isEmpty()) {
            return;
        }

        try {
            for (Long loanId : loanIds) {
                invalidateCache(loanId);
            }
            log.debug("已批量失效{}个贷款的验证缓存", loanIds.size());
        } catch (Exception e) {
            log.error("批量失效验证缓存失败", e);
        }
    }

    /**
     * 预加载验证结果缓存
     *
     * @param validations 验证结果列表
     */
    public void preloadValidationCache(List<LoanConsistencyValidation> validations) {
        if (validations == null || validations.isEmpty()) {
            return;
        }

        String lockKey = "preload_validation_cache";
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取分布式锁，避免重复预加载
            if (lock.tryLock(0, LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
                try {
                    for (LoanConsistencyValidation validation : validations) {
                        if (validation.getLoanId() != null) {
                            cacheValidationResult(validation.getLoanId(), validation);
                        }
                    }
                    log.info("已预加载{}个验证结果到缓存", validations.size());
                } finally {
                    lock.unlock();
                }
            } else {
                log.debug("无法获取预加载锁，跳过预加载操作");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("预加载验证缓存被中断", e);
        } catch (Exception e) {
            log.error("预加载验证缓存失败", e);
        }
    }

    /**
     * 清除所有验证缓存
     */
    public void clearAllValidationCache() {
        try {
            Collection<String> keys = redisCache.keys(CacheConstants.LOAN_VALIDATION_KEY + "*");
            if (keys != null && !keys.isEmpty()) {
                redisCache.deleteObject(keys);
                log.info("已清除{}个验证缓存", keys.size());
            }
        } catch (Exception e) {
            log.error("清除所有验证缓存失败", e);
        }
    }

    /**
     * 缓存验证统计信息
     *
     * @param statistics 统计信息
     */
    public void cacheValidationStatistics(ValidationStatistics statistics) {
        if (statistics == null || statistics.getStatisticsDate() == null) {
            return;
        }

        try {
            String cacheKey = buildStatisticsCacheKey(statistics.getStatisticsDate());
            redisCache.setCacheObject(cacheKey, statistics, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
            log.debug("已缓存验证统计信息，日期：{}", statistics.getStatisticsDate());
        } catch (Exception e) {
            log.error("缓存验证统计信息失败", e);
        }
    }

    /**
     * 获取缓存的验证统计信息
     *
     * @param date 统计日期
     * @return 统计信息，如果缓存中不存在则返回null
     */
    public ValidationStatistics getCachedValidationStatistics(Date date) {
        if (date == null) {
            return null;
        }

        try {
            String cacheKey = buildStatisticsCacheKey(date);
            return redisCache.getCacheObject(cacheKey);
        } catch (Exception e) {
            log.error("获取缓存验证统计信息失败，日期：{}", date, e);
            return null;
        }
    }

    /**
     * 检查缓存是否存在
     *
     * @param loanId 贷款ID
     * @return true如果缓存存在，否则false
     */
    public boolean isCacheExists(Long loanId) {
        if (loanId == null) {
            return false;
        }

        try {
            String cacheKey = buildValidationCacheKey(loanId);
            return redisCache.hasKey(cacheKey);
        } catch (Exception e) {
            log.error("检查缓存存在性失败，loanId: {}", loanId, e);
            return false;
        }
    }

    /**
     * 获取缓存剩余过期时间
     *
     * @param loanId 贷款ID
     * @return 剩余过期时间（秒），-1表示永不过期，-2表示key不存在
     */
    public long getCacheExpireTime(Long loanId) {
        if (loanId == null) {
            return -2;
        }

        try {
            String cacheKey = buildValidationCacheKey(loanId);
            return redisCache.getExpire(cacheKey);
        } catch (Exception e) {
            log.error("获取缓存过期时间失败，loanId: {}", loanId, e);
            return -2;
        }
    }

    /**
     * 刷新缓存过期时间
     *
     * @param loanId 贷款ID
     */
    public void refreshCacheExpire(Long loanId) {
        if (loanId == null) {
            return;
        }

        try {
            String cacheKey = buildValidationCacheKey(loanId);
            if (redisCache.hasKey(cacheKey)) {
                redisCache.expire(cacheKey, CACHE_EXPIRE_MINUTES * 60);
                log.debug("已刷新贷款{}的缓存过期时间", loanId);
            }
        } catch (Exception e) {
            log.error("刷新缓存过期时间失败，loanId: {}", loanId, e);
        }
    }

    /**
     * 构建验证结果缓存键
     *
     * @param loanId 贷款ID
     * @return 缓存键
     */
    private String buildValidationCacheKey(Long loanId) {
        return CacheConstants.LOAN_VALIDATION_KEY + loanId;
    }

    /**
     * 构建统计信息缓存键
     *
     * @param date 统计日期
     * @return 缓存键
     */
    private String buildStatisticsCacheKey(Date date) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        return CacheConstants.VALIDATION_STATS_KEY + formatter.format(date);
    }
}