package tech.easyflow.ai.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.plugin.workflow.dependency.WorkflowPluginDependencyService;
import tech.easyflow.ai.service.AgentResourceReferenceService;
import tech.easyflow.ai.service.DocumentCollectionService;
import tech.easyflow.ai.service.ResourceOfflineImpactService;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.ai.vo.OfflineImpactBindingVo;
import tech.easyflow.ai.vo.OfflineImpactCheckVo;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 资源下线影响检查与 Agent 静默解绑实现。
 */
@Service
public class ResourceOfflineImpactServiceImpl implements ResourceOfflineImpactService {

    private static final String KNOWLEDGE_NODE_TYPE = "knowledgeNode";

    private final WorkflowService workflowService;
    private final DocumentCollectionService documentCollectionService;
    private final WorkflowPluginDependencyService workflowPluginDependencyService;
    private final AgentResourceReferenceService agentResourceReferenceService;

    /**
     * 创建资源下线影响服务。
     *
     * @param workflowService 工作流服务
     * @param documentCollectionService 知识库服务
     * @param workflowPluginDependencyService 工作流插件依赖服务
     * @param agentResourceReferenceService Agent 资源引用服务
     */
    public ResourceOfflineImpactServiceImpl(WorkflowService workflowService,
                                            DocumentCollectionService documentCollectionService,
                                            WorkflowPluginDependencyService workflowPluginDependencyService,
                                            AgentResourceReferenceService agentResourceReferenceService) {
        this.workflowService = workflowService;
        this.documentCollectionService = documentCollectionService;
        this.workflowPluginDependencyService = workflowPluginDependencyService;
        this.agentResourceReferenceService = agentResourceReferenceService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public OfflineImpactCheckVo checkWorkflowImpact(BigInteger workflowId) {
        List<OfflineImpactBindingVo> agentBindings = listAgentsByWorkflowId(workflowId);
        List<OfflineImpactBindingVo> pluginBindings =
                workflowPluginDependencyService.listPluginsByWorkflowId(workflowId);
        OfflineImpactCheckVo result = new OfflineImpactCheckVo();
        result.setCanProceed(true);
        result.setAgentBindings(agentBindings);
        result.setHasAgentBindings(!agentBindings.isEmpty());
        result.setPluginBindings(pluginBindings);
        result.setHasPluginBindings(!pluginBindings.isEmpty());
        result.setWorkflowUsages(Collections.emptyList());
        result.setHasWorkflowUsages(false);
        result.setMessage(resolveWorkflowOfflineImpactMessage(agentBindings, pluginBindings));
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public OfflineImpactCheckVo checkKnowledgeImpact(BigInteger knowledgeId) {
        List<OfflineImpactBindingVo> agentBindings = listAgentsByKnowledgeId(knowledgeId);
        List<OfflineImpactBindingVo> workflowUsages = listWorkflowsUsingKnowledge(knowledgeId);
        OfflineImpactCheckVo result = new OfflineImpactCheckVo();
        result.setAgentBindings(agentBindings);
        result.setHasAgentBindings(!agentBindings.isEmpty());
        result.setWorkflowUsages(workflowUsages);
        result.setHasWorkflowUsages(!workflowUsages.isEmpty());
        result.setCanProceed(workflowUsages.isEmpty());
        result.setMessage(workflowUsages.isEmpty()
                ? (agentBindings.isEmpty()
                ? "当前知识库下线后不会影响已有绑定"
                : "当前知识库下线成功后，将自动从相关智能体中解绑")
                : "当前知识库仍被工作流使用，请先调整工作流后再下线");
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void unbindWorkflowFromAgents(BigInteger workflowId) {
        agentResourceReferenceService.unbindWorkflow(workflowId);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void unbindKnowledgeFromAgents(BigInteger knowledgeId) {
        agentResourceReferenceService.unbindKnowledge(knowledgeId);
    }

    /**
     * 汇总绑定指定工作流的 Agent。
     *
     * @param workflowId 工作流 ID
     * @return 去重后的 Agent 摘要
     */
    private List<OfflineImpactBindingVo> listAgentsByWorkflowId(BigInteger workflowId) {
        return agentResourceReferenceService.listAgentsByWorkflowId(workflowId);
    }

    /**
     * 汇总绑定指定知识库的 Agent。
     *
     * @param knowledgeId 知识库 ID
     * @return 去重后的 Agent 摘要
     */
    private List<OfflineImpactBindingVo> listAgentsByKnowledgeId(BigInteger knowledgeId) {
        return agentResourceReferenceService.listAgentsByKnowledgeId(knowledgeId);
    }

    /**
     * 查询仍在设计内容中引用指定知识库的工作流。
     *
     * @param knowledgeId 知识库 ID
     * @return 工作流摘要
     */
    private List<OfflineImpactBindingVo> listWorkflowsUsingKnowledge(BigInteger knowledgeId) {
        DocumentCollection knowledge = documentCollectionService.getById(knowledgeId);
        if (knowledge == null) {
            throw new BusinessException("知识库不存在，无法检查下线影响");
        }
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(Workflow::getId, Workflow::getTitle, Workflow::getContent)
                .eq(Workflow::getTenantId, knowledge.getTenantId());
        List<Workflow> workflows = workflowService.list(queryWrapper);
        if (workflows == null || workflows.isEmpty()) {
            return Collections.emptyList();
        }
        List<OfflineImpactBindingVo> result = new ArrayList<>();
        for (Workflow workflow : workflows) {
            if (workflow == null || workflow.getId() == null) {
                continue;
            }
            if (containsKnowledgeReference(workflow.getContent(), knowledgeId)) {
                OfflineImpactBindingVo item = new OfflineImpactBindingVo();
                item.setId(workflow.getId());
                item.setTitle(workflow.getTitle());
                result.add(item);
            }
        }
        return result;
    }

    /**
     * 生成工作流下线影响提示。
     *
     * @param agentBindings Agent 绑定
     * @param pluginBindings 插件绑定
     * @return 提示信息
     */
    private String resolveWorkflowOfflineImpactMessage(List<OfflineImpactBindingVo> agentBindings,
                                                       List<OfflineImpactBindingVo> pluginBindings) {
        if (!pluginBindings.isEmpty() && !agentBindings.isEmpty()) {
            return "当前工作流被插件和智能体引用，下线后插件将不可用，智能体将自动解绑";
        }
        if (!pluginBindings.isEmpty()) {
            return "当前工作流被插件引用，下线后相关插件将不可用";
        }
        if (!agentBindings.isEmpty()) {
            return "当前工作流下线成功后，将自动从相关智能体中解绑";
        }
        return "当前工作流下线后不会影响已有绑定";
    }

    /**
     * 判断工作流内容是否引用指定知识库。
     *
     * @param content 工作流内容
     * @param knowledgeId 知识库 ID
     * @return 是否引用
     */
    private boolean containsKnowledgeReference(String content, BigInteger knowledgeId) {
        if (!StringUtils.hasText(content) || knowledgeId == null) {
            return false;
        }
        try {
            Object parsed = JSON.parse(content);
            if (!(parsed instanceof JSONObject root)) {
                throw new BusinessException("工作流定义格式异常，无法确认知识库下线影响");
            }
            JSONArray nodes = root.getJSONArray("nodes");
            if (nodes == null || nodes.isEmpty()) {
                return false;
            }
            String expected = knowledgeId.toString();
            for (int i = 0; i < nodes.size(); i++) {
                JSONObject node = nodes.getJSONObject(i);
                if (node == null || !KNOWLEDGE_NODE_TYPE.equals(node.getString("type"))) {
                    continue;
                }
                JSONObject data = node.getJSONObject("data");
                if (data == null) {
                    continue;
                }
                Object rawKnowledgeId = data.get("knowledgeId");
                if (rawKnowledgeId != null && expected.equals(String.valueOf(rawKnowledgeId))) {
                    return true;
                }
            }
            return false;
        } catch (BusinessException exception) {
            throw exception;
        } catch (Exception exception) {
            throw new BusinessException("工作流定义解析失败，无法确认知识库下线影响");
        }
    }
}
