package com.sonic.common.ratelimit.impl;

import java.util.Objects;

import com.sonic.common.AppRuntime;
import com.sonic.common.enums.AppEnv;
import org.springframework.data.redis.core.RedisTemplate;

import com.sonic.common.ratelimit.RateLimiter;
import com.sonic.common.ratelimit.RateLimiterClient;

import lombok.AccessLevel;
import lombok.Data;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RateLimiterClientImpl implements RateLimiterClient {
    @Setter(AccessLevel.PROTECTED)
    private AppRuntime appRuntime;
    @Setter(AccessLevel.PROTECTED)
    private RedisTemplate redisTemplate;

    @Override
    public RateLimiter build(RateLimiterReq rateLimiterReq) {
        return RedisRateLimiter.builder()
                .windowType(rateLimiterReq.getWindowType())
                .limitRules(rateLimiterReq.getRules())
                .limiterKey(rateLimiterReq.getLimiterKey())
                .redisTemplate(redisTemplate)
                .appRuntime(appRuntime)
                .build();
    }

    public static RateLimiterClientImpl.Builder builder() {
        return new RateLimiterClientImpl.Builder();
    }

    @Data
    public static class Builder {

        private RedisTemplate redisTemplate;
        private AppRuntime appRuntime;

        public RateLimiterClientImpl.Builder redisTemplate(RedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
            return this;
        }

        public RateLimiterClientImpl.Builder appRuntime(AppRuntime appRuntime) {
            this.appRuntime = appRuntime;
            return this;
        }

        public RateLimiterClient build() {
            if (appRuntime.getEnv() == AppEnv.unittest) {
                return DummyRateLimiter::new;
            }
            //单元测试环境也构建同样的RateLimiterClient
            Objects.requireNonNull(redisTemplate);

            RateLimiterClientImpl client = new RateLimiterClientImpl();
            client.setRedisTemplate(redisTemplate);
            client.setAppRuntime(appRuntime);

            return client;
        }
    }
}
