package tech.easyflow.ai.plugin.workflow.availability;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PluginType;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.plugin.workflow.snapshot.WorkflowPluginSnapshotResolver;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.service.CategoryPermissionService;
import tech.easyflow.system.service.ResourceAccessService;

import java.math.BigInteger;
import java.util.Map;

/**
 * 工作流插件实时可用性判定实现。
 */
@Service
public class WorkflowPluginAvailabilityServiceImpl implements WorkflowPluginAvailabilityService {

    private final WorkflowService workflowService;
    private final ResourceAccessService resourceAccessService;
    private final CategoryPermissionService categoryPermissionService;
    private final WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver;

    public WorkflowPluginAvailabilityServiceImpl(WorkflowService workflowService,
                                                 ResourceAccessService resourceAccessService,
                                                 CategoryPermissionService categoryPermissionService,
                                                 WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver) {
        this.workflowService = workflowService;
        this.resourceAccessService = resourceAccessService;
        this.categoryPermissionService = categoryPermissionService;
        this.workflowPluginSnapshotResolver = workflowPluginSnapshotResolver;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public WorkflowPluginAvailabilityDecision evaluateForCurrentUser(Plugin plugin) {
        return evaluate(plugin, SaTokenUtil.getLoginAccount());
    }

    @Override
    public WorkflowPluginAvailabilityDecision evaluate(Plugin plugin, LoginAccount loginAccount) {
        WorkflowPluginAvailabilityDecision decision = new WorkflowPluginAvailabilityDecision();
        decision.setVisible(true);
        decision.setAvailable(true);
        if (plugin == null || !PluginType.isWorkflow(plugin.getType())) {
            return decision;
        }
        BigInteger workflowId = plugin.getWorkflowId();
        if (workflowId == null) {
            return unavailable(decision, "WORKFLOW_BINDING_MISSING", "当前插件未绑定工作流");
        }

        Workflow workflow = workflowService.getById(workflowId);
        if (workflow == null) {
            return unavailable(decision, "WORKFLOW_NOT_FOUND", "当前插件绑定的工作流不存在");
        }
        decision.setWorkflowTitle(workflow.getTitle());

        Map<String, Object> snapshot = workflow.getPublishedSnapshotJson();
        boolean snapshotPresent = !CollectionUtils.isEmpty(snapshot);
        decision.setSnapshotPresent(snapshotPresent);
        if (!snapshotPresent) {
            return unavailable(decision, "WORKFLOW_SNAPSHOT_MISSING", "当前插件绑定工作流没有可用发布快照");
        }

        PublishStatus publishStatus = PublishStatus.from(workflow.getPublishStatus());
        if (!publishStatus.isExternallyVisible()) {
            return unavailable(decision, "WORKFLOW_OFFLINE", "当前节点绑定工作流已下线");
        }
        Workflow publishedWorkflow = workflowService.toPublishedView(workflow);
        if (!workflowPluginSnapshotResolver.isSupportedForWorkflowPlugin(publishedWorkflow)) {
            return unavailable(decision, "WORKFLOW_MULTI_END_UNSUPPORTED", "当前节点绑定工作流包含多个结束节点，暂不支持作为插件使用");
        }

        if (!resourceAccessService.canAccess(loginAccount, CategoryResourceType.WORKFLOW, workflow, ResourceAction.USE)) {
            return unavailable(decision, "WORKFLOW_NO_PERMISSION", "当前用户无权使用目标工作流");
        }
        return decision;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean canViewUnavailableInManagement(Plugin plugin) {
        if (plugin == null) {
            return false;
        }
        if (categoryPermissionService.isCurrentSuperAdmin()) {
            return true;
        }
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        if (loginAccount == null || loginAccount.getId() == null || plugin.getCreatedBy() == null) {
            return false;
        }
        return loginAccount.getId().equals(BigInteger.valueOf(plugin.getCreatedBy()));
    }

    /**
     * 标记为不可见且不可用。
     *
     * @param decision     判定结果
     * @param reasonCode   原因编码
     * @param reasonMessage 原因说明
     * @return 判定结果
     */
    private WorkflowPluginAvailabilityDecision unavailable(WorkflowPluginAvailabilityDecision decision,
                                                           String reasonCode,
                                                           String reasonMessage) {
        decision.setVisible(false);
        decision.setAvailable(false);
        decision.setReasonCode(reasonCode);
        decision.setReasonMessage(reasonMessage);
        return decision;
    }
}
