package com.eactive.eai.common.inflow;

import io.github.bucket4j.local.LocalBucket;

/**
 * 그룹 유량제어 전용 버킷
 * 초당 임계치와 추가 임계치를 별도 버킷으로 관리하여 개별 토큰 조회 가능
 */
public class CustomGroupBucket {
    private LocalBucket perSecondBucket;   // 초당 임계치 버킷 (null 가능)
    private LocalBucket thresholdBucket;   // 추가 임계치 버킷 (null 가능)
    private InflowGroupVO groupVo;

    public CustomGroupBucket(LocalBucket perSecondBucket, LocalBucket thresholdBucket, InflowGroupVO groupVo) {
        this.perSecondBucket = perSecondBucket;
        this.thresholdBucket = thresholdBucket;
        this.groupVo = groupVo;
    }

    /** 소비 결과: 성공 */
    public static final String RESULT_PASS = null;
    /** 소비 결과: 초당 임계치 초과 */
    public static final String RESULT_BLOCKED_PER_SECOND = "PER_SECOND";
    /** 소비 결과: 추가 임계치 초과 */
    public static final String RESULT_BLOCKED_THRESHOLD = "THRESHOLD";

    /**
     * 두 버킷 모두에서 토큰 소비 시도
     * @return null이면 성공, "PER_SECOND" 또는 "THRESHOLD"면 해당 버킷에서 차단
     */
    public String tryConsume() {
        boolean perSecondPass = (perSecondBucket == null) || perSecondBucket.tryConsume(1);
        if (!perSecondPass) {
            return RESULT_BLOCKED_PER_SECOND;
        }

        boolean thresholdPass = (thresholdBucket == null) || thresholdBucket.tryConsume(1);
        if (!thresholdPass) {
            // 초당 버킷에서 이미 소비했으므로 롤백은 불가 (Token Bucket 특성상)
            // 하지만 초당 버킷은 빠르게 리필되므로 실질적 영향 미미
            return RESULT_BLOCKED_THRESHOLD;
        }

        return RESULT_PASS;
    }

    /**
     * 초당 임계치 버킷의 사용 가능한 토큰 수
     */
    public long getPerSecondAvailableTokens() {
        return (perSecondBucket != null) ? perSecondBucket.getAvailableTokens() : -1;
    }

    /**
     * 추가 임계치 버킷의 사용 가능한 토큰 수
     */
    public long getThresholdAvailableTokens() {
        return (thresholdBucket != null) ? thresholdBucket.getAvailableTokens() : -1;
    }

    public LocalBucket getPerSecondBucket() {
        return perSecondBucket;
    }

    public void setPerSecondBucket(LocalBucket perSecondBucket) {
        this.perSecondBucket = perSecondBucket;
    }

    public LocalBucket getThresholdBucket() {
        return thresholdBucket;
    }

    public void setThresholdBucket(LocalBucket thresholdBucket) {
        this.thresholdBucket = thresholdBucket;
    }

    public InflowGroupVO getGroupVo() {
        return groupVo;
    }

    public void setGroupVo(InflowGroupVO groupVo) {
        this.groupVo = groupVo;
    }
}
