package com.eactive.eai.common.inflow.dual;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

import com.eactive.eai.common.inflow.InflowTargetVO;

/**
 * DualInflowControlManager.makeBucket() 버킷 생성 동작 검증.
 *
 * <p>검증 포인트:
 * - threshold/perSecond 버킷이 실제로 생성되는지
 * - 할당량 이내 spike는 통과하고 초과 burst는 차단되는지
 * - perSecond/threshold 중 어느 쪽이 binding 제약인지 구분되는지
 */
class DualInflowControlManagerMakeBucketTest {

    private final DualInflowControlManager manager = new DualInflowControlManager();

    private InflowTargetVO vo(long perSecond, long threshold, String timeUnit) {
        InflowTargetVO vo = new InflowTargetVO();
        vo.setName("TEST");
        vo.setThresholdPerSecond(perSecond);
        vo.setThreshold(threshold);
        vo.setThresholdTimeUnit(timeUnit);
        vo.setActivate(true);
        return vo;
    }

    // =========================================================================
    // threshold 단독 (5건/분)
    // =========================================================================

    @Test
    void thresholdOnly_spikePasses_thenBurstBlocked() {
        DualCustomBucket bucket = manager.makeBucket(vo(0, 5, "MIN"));

        for (int i = 0; i < 5; i++) assertNull(bucket.tryConsume());
        assertEquals(DualCustomBucket.RESULT_BLOCKED_THRESHOLD, bucket.tryConsume());
    }

    // =========================================================================
    // perSecond 단독
    // =========================================================================

    @Test
    void perSecondOnly_spikePasses_thenBurstBlocked() {
        DualCustomBucket bucket = manager.makeBucket(vo(5, 0, null));

        for (int i = 0; i < 5; i++) assertNull(bucket.tryConsume());
        assertEquals(DualCustomBucket.RESULT_BLOCKED_PER_SECOND, bucket.tryConsume());
    }

    // =========================================================================
    // perSecond + threshold 동시 설정 — binding 제약 구분
    // =========================================================================

    @Test
    void both_perSecondIsBinding_blockedByPerSecond() {
        // perSecond=3 이 binding: threshold=100/MIN은 여유 있음
        DualCustomBucket bucket = manager.makeBucket(vo(3, 100, "MIN"));

        for (int i = 0; i < 3; i++) assertNull(bucket.tryConsume());
        assertEquals(DualCustomBucket.RESULT_BLOCKED_PER_SECOND, bucket.tryConsume());
    }

    @Test
    void both_thresholdIsBinding_blockedByThreshold() {
        // threshold=3/MIN 이 binding: perSecond=100은 여유 있음
        DualCustomBucket bucket = manager.makeBucket(vo(100, 3, "MIN"));

        for (int i = 0; i < 3; i++) assertNull(bucket.tryConsume());
        assertEquals(DualCustomBucket.RESULT_BLOCKED_THRESHOLD, bucket.tryConsume());
    }

    // =========================================================================
    // 비활성 / 조건 미충족 → null 반환
    // =========================================================================

    @Test
    void inactiveVO_returnsNull() {
        InflowTargetVO vo = vo(5, 0, null);
        vo.setActivate(false);
        assertNull(manager.makeBucket(vo));
    }

    @Test
    void noLimitsSet_returnsNull() {
        assertNull(manager.makeBucket(vo(0, 0, null)));
    }
}
