package tech.easyflow.system.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.common.cache.RedisLockExecutor;
import tech.easyflow.system.entity.SysApiKey;
import tech.easyflow.system.entity.SysApiKeyResourceMapping;
import tech.easyflow.system.mapper.SysApiKeyResourceMappingMapper;
import tech.easyflow.system.service.SysApiKeyResourceMappingService;

import javax.annotation.Resource;
import java.time.Duration;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * apikey-请求接口表 服务层实现。
 *
 * @author 12076
 * @since 2025-12-01
 */
@Service
public class SysApiKeyResourceMappingServiceImpl extends ServiceImpl<SysApiKeyResourceMappingMapper, SysApiKeyResourceMapping>  implements SysApiKeyResourceMappingService {

    private static final String API_KEY_MAPPING_LOCK_PREFIX = "easyflow:lock:sys:apikey:mapping:";
    private static final Duration LOCK_WAIT_TIMEOUT = Duration.ofSeconds(2);
    private static final Duration LOCK_LEASE_TIMEOUT = Duration.ofSeconds(10);

    @Resource
    private RedisLockExecutor redisLockExecutor;

    /**
     * 批量授权apiKey接口
     * @param entity
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void authInterface(SysApiKey entity) {
        BigInteger apiKeyId = entity.getId();
        if (apiKeyId == null) {
            return;
        }
        redisLockExecutor.executeWithLock(API_KEY_MAPPING_LOCK_PREFIX + apiKeyId, LOCK_WAIT_TIMEOUT, LOCK_LEASE_TIMEOUT, () -> {
            QueryWrapper removeWrapper = QueryWrapper.create()
                .eq(SysApiKeyResourceMapping::getApiKeyId, apiKeyId)
                .isNull(SysApiKeyResourceMapping::getResourceType);
            this.remove(removeWrapper);
            if (entity.getPermissionIds() == null || entity.getPermissionIds().isEmpty()) {
                return;
            }
            Set<BigInteger> uniqueResourceIds = new LinkedHashSet<>(entity.getPermissionIds());
            List<SysApiKeyResourceMapping> rows = new ArrayList<>(uniqueResourceIds.size());
            for (BigInteger resourceId : uniqueResourceIds) {
                if (resourceId == null) {
                    continue;
                }
                SysApiKeyResourceMapping sysApiKeyResourcePermissionRelationship = new SysApiKeyResourceMapping();
                sysApiKeyResourcePermissionRelationship.setApiKeyId(apiKeyId);
                sysApiKeyResourcePermissionRelationship.setApiKeyResourceId(resourceId);
                rows.add(sysApiKeyResourcePermissionRelationship);
            }
            if (!rows.isEmpty()) {
                this.saveBatch(rows);
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeScopedMappings(BigInteger apiKeyId, String resourceType, BigInteger resourceTargetId) {
        if (apiKeyId == null || resourceTargetId == null || resourceType == null || resourceType.isBlank()) {
            return;
        }
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(SysApiKeyResourceMapping::getApiKeyId, apiKeyId)
            .eq(SysApiKeyResourceMapping::getResourceType, resourceType)
            .eq(SysApiKeyResourceMapping::getResourceTargetId, resourceTargetId);
        remove(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeScopedMappings(BigInteger apiKeyId, String resourceType) {
        if (apiKeyId == null || resourceType == null || resourceType.isBlank()) {
            return;
        }
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(SysApiKeyResourceMapping::getApiKeyId, apiKeyId)
            .eq(SysApiKeyResourceMapping::getResourceType, resourceType);
        remove(wrapper);
    }
}
