package com.bcxin.Infrastructure.messages.components;

import com.bcxin.Infrastructures.components.RetryProvider;
import com.bcxin.Infrastructures.components.UniqueVerificationCodeGenerator;
import com.bcxin.Infrastructures.components.models.VerificationCode;
import com.bcxin.Infrastructures.exceptions.BadTenantException;
import org.redisson.api.RScript;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class UniqueVerificationCodeGeneratorImpl implements UniqueVerificationCodeGenerator {
    private static final Logger logger = LoggerFactory.getLogger(UniqueVerificationCodeGeneratorImpl.class);
    private final RedissonClient redissonClient;
    private final RetryProvider retryProvider;

    public UniqueVerificationCodeGeneratorImpl(RedissonClient redissonClient, RetryProvider retryProvider) {
        this.redissonClient = redissonClient;
        this.retryProvider = retryProvider;
    }

    @Override
    public VerificationCode execute(String key) {
        AtomicReference<String> gnCode = new AtomicReference<>();
        AtomicInteger retryIndex = new AtomicInteger(0);
        retryProvider.execute(() -> {
            int tryIndex = 0;
            int length = 8;
            do {
                String code = generateRandomString(length); // 假设我们需要一个8位的验证码
                if (generateAndStoreUniqueCode(code)) {
                    gnCode.set(code);
                    logger.error("生成的唯一值(length={})信息:code={};index={}", length, code, tryIndex);
                    return;
                }
            }
            while (retryIndex.incrementAndGet() < 100);
            throw new BadTenantException("验证码生成失败, 请重新生成");
        }, 5);

        return VerificationCode.create(gnCode.get(), retryIndex.get());
    }

    public boolean generateAndStoreUniqueCode(String code) {
        String luaScript =
                "local key = KEYS[1]\n" +
                        "local code = ARGV[1]\n" +
                        "local exists = redis.call('SISMEMBER', key, code)\n" +
                        "if exists == 0 then\n" +
                        "    redis.call('SADD', key, code)\n" +
                        "    redis.call('EXPIRE', key, 28800)\n" + // 设置过期时间为8小时
                        "    return 1\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";

        RScript script = redissonClient.getScript();
        String key = "unique_vf_codes"; // Redis集合键名

        Object result = script.eval(RScript.Mode.READ_WRITE, luaScript,
                RScript.ReturnType.BOOLEAN,
                Collections.singletonList(key),
                Collections.singletonList(code));

        return (Boolean) result;
    }

    private static final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private static String generateRandomString(int length) {
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            int index = (int) (Math.random() * characters.length());
            sb.append(characters.charAt(index));
        }

        return sb.toString();
    }
}
