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 tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.entity.SysApiKey;
import tech.easyflow.system.entity.SysApiKeyResource;
import tech.easyflow.system.entity.SysApiKeyResourceMapping;
import tech.easyflow.system.mapper.SysApiKeyMapper;
import tech.easyflow.system.service.SysApiKeyResourceMappingService;
import tech.easyflow.system.service.SysApiKeyResourceService;
import tech.easyflow.system.service.SysApiKeyService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2025-04-18
 */
@Service
public class SysApiKeyServiceImpl extends ServiceImpl<SysApiKeyMapper, SysApiKey> implements SysApiKeyService {

    @Resource
    private SysApiKeyResourceMappingService mappingService;
    @Resource
    private SysApiKeyResourceService resourceService;

    @Override
    public void checkApikeyPermission(String apiKey, String requestURI) {
        SysApiKey sysApiKey = getSysApiKey(apiKey);
        List<String> candidateRequestUris = getCandidateRequestUris(requestURI);
        QueryWrapper w = QueryWrapper.create();
        w.in(SysApiKeyResource::getRequestInterface, candidateRequestUris);
        List<SysApiKeyResource> resources = resourceService.list(w);
        if (resources == null || resources.isEmpty()) {
            throw new BusinessException("该接口不存在");
        }
        List<BigInteger> resourceIds = resources.stream()
                .map(SysApiKeyResource::getId)
                .toList();
        QueryWrapper wm = QueryWrapper.create();
        wm.eq(SysApiKeyResourceMapping::getApiKeyId, sysApiKey.getId());
        wm.in(SysApiKeyResourceMapping::getApiKeyResourceId, resourceIds);
        long count = mappingService.count(wm);
        if (count == 0) {
            throw new BusinessException("该apiKey无权限访问该接口");
        }
    }

    private List<String> getCandidateRequestUris(String requestURI) {
        List<String> uris = new ArrayList<>();
        uris.add(requestURI);
        if ("/v1/chat/completions".equals(requestURI)) {
            uris.add("/public-api/openai/v1/chat/completions");
        } else if ("/public-api/openai/v1/chat/completions".equals(requestURI)) {
            uris.add("/v1/chat/completions");
        }
        return uris;
    }

    @Override
    public SysApiKey getSysApiKey(String apiKey) {
        QueryWrapper w = QueryWrapper.create();
        w.eq(SysApiKey::getApiKey, apiKey);
        SysApiKey one = getOne(w);
        if (one == null || one.getStatus() == 0) {
            throw new BusinessException("apiKey 不存在或已禁用");
        }
        if (one.getExpiredAt() != null && one.getExpiredAt().getTime() < new Date().getTime()) {
            throw new BusinessException("apiKey 已过期");
        }
        return one;
    }

    @Override
    public void checkResourceScope(BigInteger apiKeyId, String requestURI, String resourceType, BigInteger resourceTargetId, String actionScope) {
        List<String> candidateRequestUris = getCandidateRequestUris(requestURI);
        QueryWrapper resourceWrapper = QueryWrapper.create();
        resourceWrapper.in(SysApiKeyResource::getRequestInterface, candidateRequestUris);
        List<SysApiKeyResource> resources = resourceService.list(resourceWrapper);
        if (resources == null || resources.isEmpty()) {
            throw new BusinessException("该接口不存在");
        }
        List<BigInteger> resourceIds = resources.stream()
            .map(SysApiKeyResource::getId)
            .toList();
        QueryWrapper exactScopeWrapper = QueryWrapper.create()
            .eq(SysApiKeyResourceMapping::getApiKeyId, apiKeyId)
            .in(SysApiKeyResourceMapping::getApiKeyResourceId, resourceIds)
            .eq(SysApiKeyResourceMapping::getResourceType, resourceType)
            .eq(SysApiKeyResourceMapping::getResourceTargetId, resourceTargetId)
            .eq(SysApiKeyResourceMapping::getActionScope, actionScope);
        if (mappingService.count(exactScopeWrapper) > 0) {
            return;
        }
        QueryWrapper globalScopeWrapper = QueryWrapper.create();
        globalScopeWrapper.eq(SysApiKeyResourceMapping::getApiKeyId, apiKeyId);
        globalScopeWrapper.in(SysApiKeyResourceMapping::getApiKeyResourceId, resourceIds);
        globalScopeWrapper.eq(SysApiKeyResourceMapping::getResourceType, resourceType);
        globalScopeWrapper.isNull(SysApiKeyResourceMapping::getResourceTargetId);
        globalScopeWrapper.eq(SysApiKeyResourceMapping::getActionScope, actionScope);
        if (mappingService.count(globalScopeWrapper) == 0) {
            throw new BusinessException("该apiKey无权限访问当前资源");
        }
    }

}
