package tech.easyflow.ai.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.ai.service.WorkflowApiPermissionService;
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.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.List;

/**
 * 工作流 Public API 访问令牌授权服务实现。
 */
@Service
public class WorkflowApiPermissionServiceImpl implements WorkflowApiPermissionService {

    private static final String RESOURCE_TITLE = "工作流 API 调用";

    private static final List<String> WORKFLOW_API_URIS = List.of(
        "/public-api/workflow/getByIdOrAlias",
        "/public-api/workflow/getRunningParameters",
        "/public-api/workflow/runAsync",
        "/public-api/workflow/getChainStatus",
        "/public-api/workflow/resume"
    );

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

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replaceWorkflowApiEnabled(BigInteger apiKeyId, boolean enabled) {
        if (apiKeyId == null) {
            throw new BusinessException("系统访问令牌不能为空");
        }
        SysApiKey apiKey = sysApiKeyService.getById(apiKeyId);
        if (apiKey == null) {
            throw new BusinessException("系统访问令牌不存在");
        }
        mappingService.removeScopedMappings(apiKeyId, RESOURCE_TYPE_WORKFLOW);
        if (!enabled) {
            return;
        }

        List<SysApiKeyResourceMapping> rows = new ArrayList<>(WORKFLOW_API_URIS.size());
        for (String uri : WORKFLOW_API_URIS) {
            SysApiKeyResource resource = ensureResource(uri);
            SysApiKeyResourceMapping row = new SysApiKeyResourceMapping();
            row.setApiKeyId(apiKeyId);
            row.setApiKeyResourceId(resource.getId());
            row.setResourceType(RESOURCE_TYPE_WORKFLOW);
            row.setActionScope(ACTION_SCOPE_INVOKE);
            rows.add(row);
        }
        if (!rows.isEmpty()) {
            mappingService.saveBatch(rows);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SysApiKey assertWorkflowApi(String apiKey, String requestUri) {
        SysApiKey sysApiKey = sysApiKeyService.getSysApiKey(apiKey);
        SysApiKeyResource resource = getResource(requestUri);
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(SysApiKeyResourceMapping::getApiKeyId, sysApiKey.getId())
            .eq(SysApiKeyResourceMapping::getApiKeyResourceId, resource.getId())
            .eq(SysApiKeyResourceMapping::getResourceType, RESOURCE_TYPE_WORKFLOW)
            .isNull(SysApiKeyResourceMapping::getResourceTargetId)
            .eq(SysApiKeyResourceMapping::getActionScope, ACTION_SCOPE_INVOKE);
        if (mappingService.count(wrapper) == 0) {
            throw new BusinessException("该apiKey无权限调用工作流 API");
        }
        return sysApiKey;
    }

    /**
     * 获取工作流 Public API 资源。
     *
     * @param requestInterface 请求地址
     * @return API 资源
     */
    private SysApiKeyResource getResource(String requestInterface) {
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(SysApiKeyResource::getRequestInterface, requestInterface);
        SysApiKeyResource resource = resourceService.getOne(wrapper);
        if (resource == null) {
            throw new BusinessException("该接口不存在");
        }
        return resource;
    }

    /**
     * 确保工作流 Public API 资源已存在。
     *
     * @param requestInterface 请求地址
     * @return API 资源
     */
    private SysApiKeyResource ensureResource(String requestInterface) {
        QueryWrapper wrapper = QueryWrapper.create()
            .eq(SysApiKeyResource::getRequestInterface, requestInterface);
        SysApiKeyResource resource = resourceService.getOne(wrapper);
        if (resource != null) {
            return resource;
        }
        resource = new SysApiKeyResource();
        resource.setRequestInterface(requestInterface);
        resource.setTitle(RESOURCE_TITLE);
        resourceService.save(resource);
        return resource;
    }
}
