package com.dora.service.impl;

import com.dora.service.IdentityVerifyLimitService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.concurrent.TimeUnit;

/**
 * 实名认证请求限制服务实现类
 * 
 * 使用Redis存储每日请求计数，key格式：identity_verify_daily:{userId}:{yyyy-MM-dd}
 * 自动过期时间为24小时，确保每日重置
 *
 * @author Dora
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IdentityVerifyLimitServiceImpl implements IdentityVerifyLimitService {

    private final RedisTemplate<String, String> redisTemplate;

    @Value("${identity-verify.daily-limit:3}")
    private Integer dailyLimit;

    @Value("${identity-verify.redis-key-prefix:identity_verify_daily}")
    private String redisKeyPrefix;

    @Value("${identity-verify.enable-limit:true}")
    private Boolean enableLimit;

    @Override
    public boolean canMakeVerifyRequest(Long userId) {
        if (!enableLimit.booleanValue()) {
            log.debug("实名认证限制功能已禁用，允许请求 - userId: {}", userId);
            return true;
        }

        if (userId == null) {
            log.warn("用户ID为空，拒绝认证请求");
            return false;
        }

        try {
            int todayCount = getTodayRequestCount(userId);
            boolean canRequest = todayCount < dailyLimit;
            
            log.debug("用户 {} 今日认证请求检查 - 已请求: {}, 限制: {}, 可请求: {}", 
                    userId, todayCount, dailyLimit, canRequest);
            
            return canRequest;
            
        } catch (Exception e) {
            log.error("检查用户每日认证请求限制时发生异常，采用宽松策略允许请求 - userId: {}", userId, e);
            // Redis异常时采用宽松策略，允许请求以不影响业务
            return true;
        }
    }

    @Override
    public void incrementVerifyRequest(Long userId) {
        if (!enableLimit.booleanValue()) {
            log.debug("实名认证限制功能已禁用，跳过计数 - userId: {}", userId);
            return;
        }

        if (userId == null) {
            log.warn("用户ID为空，无法增加认证请求计数");
            return;
        }

        try {
            String key = generateRedisKey(userId);
            
            // 使用Redis的increment操作，原子性增加计数
            Long currentCount = redisTemplate.opsForValue().increment(key);
            
            if (currentCount != null) {
                if (currentCount == 1) {
                    // 第一次请求，设置过期时间为明天0点
                    long ttl = getSecondsUntilNextDay();
                    redisTemplate.expire(key, ttl, TimeUnit.SECONDS);
                    
                    log.info("用户 {} 首次今日认证请求，设置TTL: {}秒", userId, ttl);
                }
                
                log.info("用户 {} 认证请求计数增加，当前计数: {}/{}", userId, currentCount, dailyLimit);
                
                if (currentCount > dailyLimit) {
                    log.warn("用户 {} 认证请求已超过每日限制，当前: {}, 限制: {}", 
                            userId, currentCount, dailyLimit);
                }
            }
            
        } catch (Exception e) {
            log.error("增加用户认证请求计数时发生异常，但不影响业务流程 - userId: {}", userId, e);
            // Redis异常不应影响认证流程的继续进行
        }
    }

    @Override
    public int getTodayRequestCount(Long userId) {
        if (!enableLimit.booleanValue() || userId == null) {
            return 0;
        }

        try {
            String key = generateRedisKey(userId);
            String countStr = redisTemplate.opsForValue().get(key);
            
            if (countStr == null) {
                log.debug("用户 {} 今日暂无认证请求记录", userId);
                return 0;
            }
            
            int count = Integer.parseInt(countStr);
            log.debug("用户 {} 今日认证请求次数: {}", userId, count);
            return count;
            
        } catch (NumberFormatException e) {
            log.error("解析用户认证请求计数时格式错误 - userId: {}", userId, e);
            return 0;
        } catch (Exception e) {
            log.error("获取用户今日认证请求计数时发生异常 - userId: {}", userId, e);
            return 0;
        }
    }

    @Override
    public int getRemainingRequests(Long userId) {
        if (!enableLimit.booleanValue()) {
            return dailyLimit; // 功能禁用时返回最大限制数
        }

        int todayCount = getTodayRequestCount(userId);
        int remaining = Math.max(0, dailyLimit - todayCount);
        
        log.debug("用户 {} 剩余认证请求次数: {} (今日已用: {}/{})", 
                userId, remaining, todayCount, dailyLimit);
        
        return remaining;
    }

    @Override
    public int getDailyLimit() {
        return dailyLimit;
    }

    @Override
    public long getNextResetTime() {
        // 获取明天0点的时间戳
        LocalDateTime tomorrow = LocalDate.now().plusDays(1).atStartOfDay();
        return tomorrow.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 生成Redis存储的Key
     * 格式：{prefix}:{userId}:{yyyy-MM-dd}
     * 
     * @param userId 用户ID
     * @return Redis Key
     */
    private String generateRedisKey(Long userId) {
        String today = LocalDate.now().toString(); // yyyy-MM-dd
        return String.format("%s:%s:%s", redisKeyPrefix, userId, today);
    }

    /**
     * 计算到明天0点的秒数
     * 
     * @return 剩余秒数
     */
    private long getSecondsUntilNextDay() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime nextDay = LocalDate.now().plusDays(1).atStartOfDay();
        
        long seconds = java.time.Duration.between(now, nextDay).getSeconds();
        
        // 确保至少有1秒的TTL，避免立即过期
        return Math.max(1L, seconds);
    }
}
