package tech.easyflow.skill.gitimport;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheInvokeException;
import com.alicp.jetcache.CacheResult;
import com.alicp.jetcache.CacheResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.util.concurrent.TimeUnit;

/**
 * 对同一租户账号的 Git 仓库扫描实施短周期频控。
 */
@Component
public class SkillGitScanRateLimiter {

    private static final Logger LOG = LoggerFactory.getLogger(SkillGitScanRateLimiter.class);
    private static final String CACHE_PREFIX = "skill:git-scan:rate:";

    private final Cache<String, Object> defaultCache;
    private final SkillGitImportProperties properties;

    /**
     * 创建仓库扫描频控器。
     *
     * @param defaultCache 平台默认缓存
     * @param properties Git 导入配置
     */
    public SkillGitScanRateLimiter(@Qualifier("defaultCache") Cache<String, Object> defaultCache,
                                   SkillGitImportProperties properties) {
        this.defaultCache = defaultCache;
        this.properties = properties;
    }

    /**
     * 检查当前账号是否允许发起新的仓库扫描。
     *
     * @throws BusinessException 未登录、请求过于频繁或缓存不可用
     */
    public void check() {
        LoginAccount account = SaTokenUtil.getLoginAccount();
        if (account == null || account.getTenantId() == null || account.getId() == null) {
            throw new BusinessException(401, 401, "未登录或登录态无效");
        }
        check(account);
    }

    /**
     * 使用已认证账号执行频控检查，供契约测试复用。
     *
     * @param account 已认证账号
     * @throws BusinessException 请求过于频繁或缓存不可用
     */
    void check(LoginAccount account) {
        long intervalMillis = properties.getScanMinimumInterval().toMillis();
        String key = CACHE_PREFIX + account.getTenantId() + ":" + account.getId();
        try {
            CacheResult result = defaultCache.PUT_IF_ABSENT(
                    key, Boolean.TRUE, intervalMillis, TimeUnit.MILLISECONDS);
            if (result.getResultCode() == CacheResultCode.SUCCESS) {
                return;
            }
            if (result.getResultCode() == CacheResultCode.EXISTS) {
                throw new BusinessException(429, 42922, "Git 仓库扫描过于频繁，请稍后重试");
            }
            LOG.error("Git 仓库扫描频控缓存写入失败，code={}, message={}",
                    result.getResultCode(), result.getMessage());
            throw new BusinessException(503, 50322, "Git 仓库扫描暂不可用，请稍后重试");
        } catch (CacheInvokeException exception) {
            LOG.error("Git 仓库扫描频控缓存访问失败", exception);
            throw new BusinessException(503, 50322, "Git 仓库扫描暂不可用，请稍后重试", exception);
        }
    }
}
