package com.lesingle.modules.pub.service;

import com.lesingle.common.constants.CacheConstants;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.concurrent.TimeUnit;

/**
 * 短信验证码业务服务
 * 负责：生成验证码、存储到 Redis、校验验证码
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SmsCodeService {

    private final SmsService smsService;
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 发送短信验证码
     *
     * @param phone 手机号
     */
    public void sendCode(String phone) {
        // 检查 60 秒发送间隔
        String intervalKey = CacheConstants.SMS_INTERVAL_PREFIX + phone;
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(intervalKey))) {
            throw new BusinessException(ErrorCode.SMS_SEND_TOO_FREQUENT.getCode(),
                    ErrorCode.SMS_SEND_TOO_FREQUENT.getMessage());
        }

        // 检查每日发送次数上限
        String dailyKey = CacheConstants.SMS_DAILY_PREFIX + phone;
        String dailyCountStr = stringRedisTemplate.opsForValue().get(dailyKey);
        int dailyCount = dailyCountStr != null ? Integer.parseInt(dailyCountStr) : 0;
        if (dailyCount >= CacheConstants.SMS_DAILY_LIMIT) {
            throw new BusinessException(ErrorCode.SMS_DAILY_LIMIT_EXCEEDED.getCode(),
                    ErrorCode.SMS_DAILY_LIMIT_EXCEEDED.getMessage());
        }

        // 生成验证码
        String code = smsService.generateCode();

        // 调用短信服务发送
        smsService.sendVerifyCode(phone, code);

        // 存储验证码到 Redis（5 分钟有效）
        String codeKey = CacheConstants.SMS_CODE_PREFIX + phone;
        stringRedisTemplate.opsForValue().set(codeKey, code,
                Duration.ofMinutes(CacheConstants.SMS_CODE_EXPIRE_MINUTES));

        // 设置发送间隔（60 秒）
        stringRedisTemplate.opsForValue().set(intervalKey, "1",
                Duration.ofSeconds(CacheConstants.SMS_INTERVAL_SECONDS));

        // 递增每日发送次数（TTL 到当天 24:00）
        stringRedisTemplate.opsForValue().increment(dailyKey);
        if (dailyCount == 0) {
            // 首次发送，设置过期时间到当天结束
            long secondsUntilMidnight = Duration.between(
                    LocalDateTime.now(),
                    LocalDateTime.now().toLocalDate().plusDays(1).atTime(LocalTime.MIDNIGHT)
            ).getSeconds();
            stringRedisTemplate.expire(dailyKey, secondsUntilMidnight, TimeUnit.SECONDS);
        }

        log.info("验证码已发送：手机号={}", phone);
    }

    /**
     * 校验短信验证码
     *
     * @param phone 手机号
     * @param code  用户输入的验证码
     * @return 校验是否通过
     */
    public boolean verifyCode(String phone, String code) {
        if (code == null || code.isBlank()) {
            throw new BusinessException(ErrorCode.SMS_CODE_INVALID.getCode(),
                    "验证码不能为空");
        }

        String codeKey = CacheConstants.SMS_CODE_PREFIX + phone;
        String storedCode = stringRedisTemplate.opsForValue().get(codeKey);

        // 验证码不存在或已过期
        if (storedCode == null) {
            throw new BusinessException(ErrorCode.SMS_CODE_EXPIRED.getCode(),
                    ErrorCode.SMS_CODE_EXPIRED.getMessage());
        }

        // 验证码匹配
        if (storedCode.equals(code)) {
            // 验证成功：删除验证码（一次性使用）
            stringRedisTemplate.delete(codeKey);
            // 清除验证失败次数
            stringRedisTemplate.delete(CacheConstants.SMS_VERIFY_PREFIX + phone);
            log.info("验证码校验通过：手机号={}", phone);
            return true;
        }

        // 验证失败：递增失败次数
        String verifyKey = CacheConstants.SMS_VERIFY_PREFIX + phone;
        Long failCount = stringRedisTemplate.opsForValue().increment(verifyKey);
        if (failCount != null && failCount == 1) {
            // 首次失败，设置过期时间
            stringRedisTemplate.expire(verifyKey,
                    Duration.ofMinutes(CacheConstants.SMS_CODE_EXPIRE_MINUTES));
        }

        // 失败次数达到上限，删除验证码
        if (failCount != null && failCount >= CacheConstants.SMS_VERIFY_FAIL_LIMIT) {
            stringRedisTemplate.delete(codeKey);
            stringRedisTemplate.delete(verifyKey);
            log.warn("验证码错误次数超限，已清除：手机号={}", phone);
            throw new BusinessException(ErrorCode.SMS_CODE_EXPIRED.getCode(),
                    "验证码错误次数过多，请重新获取验证码");
        }

        throw new BusinessException(ErrorCode.SMS_CODE_INVALID.getCode(),
                ErrorCode.SMS_CODE_INVALID.getMessage());
    }
}
