package tech.easyflow.skill.gitimport;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheResult;
import org.junit.Test;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.math.BigInteger;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * {@link SkillGitScanRateLimiter} 分布式频控契约测试。
 */
public class SkillGitScanRateLimiterTest {

    /**
     * 首次扫描写入带过期时间的账号频控键。
     */
    @Test
    public void acceptsFirstScanAndStoresAccountScopedKey() {
        Cache<String, Object> cache = mock(Cache.class);
        when(cache.PUT_IF_ABSENT(eq("skill:git-scan:rate:10:20"), eq(Boolean.TRUE),
                anyLong(), eq(TimeUnit.MILLISECONDS))).thenReturn(CacheResult.SUCCESS_WITHOUT_MSG);
        SkillGitScanRateLimiter limiter = new SkillGitScanRateLimiter(cache, new SkillGitImportProperties());

        limiter.check(account());

        verify(cache).PUT_IF_ABSENT(eq("skill:git-scan:rate:10:20"), eq(Boolean.TRUE),
                eq(2_000L), eq(TimeUnit.MILLISECONDS));
    }

    /**
     * 频控键已存在时返回 HTTP 429。
     */
    @Test
    public void rejectsRepeatedScanWithinMinimumInterval() {
        Cache<String, Object> cache = mock(Cache.class);
        when(cache.PUT_IF_ABSENT(eq("skill:git-scan:rate:10:20"), eq(Boolean.TRUE),
                anyLong(), eq(TimeUnit.MILLISECONDS))).thenReturn(CacheResult.EXISTS_WITHOUT_MSG);
        SkillGitScanRateLimiter limiter = new SkillGitScanRateLimiter(cache, new SkillGitImportProperties());

        BusinessException exception = assertThrows(BusinessException.class,
                () -> limiter.check(account()));

        assertEquals(429, exception.getHttpStatus());
    }

    private LoginAccount account() {
        LoginAccount account = new LoginAccount();
        account.setTenantId(BigInteger.TEN);
        account.setId(BigInteger.valueOf(20));
        return account;
    }
}
