package tech.easyflow.agent.publish;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import org.springframework.stereotype.Component;
import tech.easyflow.agent.distributed.AgentRuntimeCommandProducer;
import tech.easyflow.agent.distributed.AgentRuntimeRouteRegistry;
import tech.easyflow.agent.entity.Agent;
import tech.easyflow.agent.entity.AgentKnowledgeBinding;
import tech.easyflow.agent.entity.AgentToolBinding;
import tech.easyflow.agent.entity.AgentSkillBinding;
import tech.easyflow.agent.runtime.AgentRunRegistry;
import tech.easyflow.agent.runtime.hitl.AgentHitlPendingService;
import tech.easyflow.agent.service.AgentKnowledgeBindingService;
import tech.easyflow.agent.service.AgentService;
import tech.easyflow.agent.service.AgentToolBindingService;
import tech.easyflow.agent.service.AgentSkillBindingService;
import tech.easyflow.agent.support.AgentBindingLockExecutor;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.publish.AbstractAiResourceLifecycleHandler;
import tech.easyflow.approval.enums.ApprovalResourceType;
import tech.easyflow.approval.service.ApprovalInstanceService;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.service.ResourceAccessService;

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

/**
 * Agent 审批资源处理器。
 */
@Component
public class AgentApprovalSubjectHandler extends AbstractAiResourceLifecycleHandler<Agent> {

    private final AgentService agentService;
    private final AgentToolBindingService agentToolBindingService;
    private final AgentKnowledgeBindingService agentKnowledgeBindingService;
    private final AgentSkillBindingService agentSkillBindingService;
    private final ResourceAccessService resourceAccessService;
    private final AgentBindingLockExecutor agentBindingLockExecutor;
    private final AgentRunRegistry agentRunRegistry;
    private final AgentHitlPendingService agentHitlPendingService;
    private final AgentRuntimeRouteRegistry agentRuntimeRouteRegistry;
    private final AgentRuntimeCommandProducer agentRuntimeCommandProducer;

    /**
     * 创建 Agent 审批资源处理器。
     *
     * @param approvalInstanceService 审批实例服务
     * @param objectMapper JSON 映射器
     * @param agentService Agent 服务
     * @param agentToolBindingService Agent 工具绑定服务
     * @param agentKnowledgeBindingService Agent 知识库绑定服务
     * @param agentSkillBindingService Agent Skill 绑定服务
     * @param resourceAccessService 资源访问服务
     * @param agentBindingLockExecutor Agent 配置锁执行器
     * @param agentRunRegistry Agent 运行态注册表
     * @param agentHitlPendingService Agent 待审批运行服务
     * @param agentRuntimeRouteRegistry Agent 分布式运行路由注册表
     * @param agentRuntimeCommandProducer Agent 远程运行命令生产者
     */
    public AgentApprovalSubjectHandler(ApprovalInstanceService approvalInstanceService,
                                       ObjectMapper objectMapper,
                                       AgentService agentService,
                                       AgentToolBindingService agentToolBindingService,
                                       AgentKnowledgeBindingService agentKnowledgeBindingService,
                                       AgentSkillBindingService agentSkillBindingService,
                                       ResourceAccessService resourceAccessService,
                                       AgentBindingLockExecutor agentBindingLockExecutor,
                                       AgentRunRegistry agentRunRegistry,
                                       AgentHitlPendingService agentHitlPendingService,
                                       AgentRuntimeRouteRegistry agentRuntimeRouteRegistry,
                                       AgentRuntimeCommandProducer agentRuntimeCommandProducer) {
        super(approvalInstanceService, objectMapper);
        this.agentService = agentService;
        this.agentToolBindingService = agentToolBindingService;
        this.agentKnowledgeBindingService = agentKnowledgeBindingService;
        this.agentSkillBindingService = agentSkillBindingService;
        this.resourceAccessService = resourceAccessService;
        this.agentBindingLockExecutor = agentBindingLockExecutor;
        this.agentRunRegistry = agentRunRegistry;
        this.agentHitlPendingService = agentHitlPendingService;
        this.agentRuntimeRouteRegistry = agentRuntimeRouteRegistry;
        this.agentRuntimeCommandProducer = agentRuntimeCommandProducer;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String resourceType() {
        return ApprovalResourceType.AGENT.getCode();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void assertPublishedAccess(Object identifier, String denyMessage) {
        Agent agent = agentService.getById(String.valueOf(identifier));
        if (agent == null || !PublishStatus.from(agent.getPublishStatus()).isExternallyVisible()
                || agent.getPublishedSnapshotJson() == null || agent.getPublishedSnapshotJson().isEmpty()) {
            throw new BusinessException(denyMessage);
        }
    }

    @Override
    protected Agent requireResource(BigInteger resourceId) {
        Agent agent = agentService.getById(resourceId);
        if (agent == null) {
            throw new BusinessException("Agent 不存在");
        }
        return agent;
    }

    @Override
    protected void assertManagePermission(Agent resource) {
        resourceAccessService.assertAccess(CategoryResourceType.AGENT, resource, ResourceAction.MANAGE, "无权限管理该 Agent");
    }

    @Override
    protected BigInteger getCategoryId(Agent resource) {
        return resource.getCategoryId();
    }

    @Override
    protected BigInteger getDeptId(Agent resource) {
        return resource.getDeptId();
    }

    @Override
    protected String getTitle(Agent resource) {
        return resource.getName();
    }

    @Override
    protected PublishStatus getCurrentStatus(Agent resource) {
        return PublishStatus.from(resource.getPublishStatus());
    }

    @Override
    protected Map<String, Object> getPublishedSnapshot(Agent resource) {
        return resource.getPublishedSnapshotJson();
    }

    @Override
    protected Map<String, Object> buildResourceSnapshot(Agent resource) {
        return agentService.buildPublishSnapshot(resource);
    }

    @Override
    protected void persistResourceState(BigInteger resourceId, PublishStatus publishStatus, BigInteger currentApprovalInstanceId) {
        agentBindingLockExecutor.execute(resourceId, () -> {
            // 生命周期操作仅更新状态字段，避免实体默认空配置覆盖 Agent 草稿配置。
            UpdateChain<Agent> updateChain = agentService.updateChain();
            updateChain.set(Agent::getPublishStatus, publishStatus.getCode());
            updateChain.set(Agent::getCurrentApprovalInstanceId, currentApprovalInstanceId);
            updateChain.eq(Agent::getId, resourceId);
            updateChain.update();
            return null;
        });
    }

    @Override
    protected void publishResource(BigInteger resourceId, Map<String, Object> resourceSnapshot, BigInteger operatorId) {
        agentBindingLockExecutor.execute(resourceId, () -> {
            UpdateChain<Agent> updateChain = agentService.updateChain();
            updateChain.set(Agent::getPublishStatus, PublishStatus.PUBLISHED.getCode());
            updateChain.set(Agent::getPublishedSnapshotJson, resourceSnapshot);
            updateChain.set(Agent::getPublishedAt, new Date());
            updateChain.set(Agent::getPublishedBy, operatorId);
            updateChain.set(Agent::getCurrentApprovalInstanceId, null);
            updateChain.eq(Agent::getId, resourceId);
            updateChain.update();
            return null;
        });
    }

    @Override
    protected void markResourceOffline(BigInteger resourceId) {
        agentBindingLockExecutor.execute(resourceId, () -> {
            UpdateChain<Agent> updateChain = agentService.updateChain();
            updateChain.set(Agent::getPublishStatus, PublishStatus.OFFLINE.getCode());
            updateChain.set(Agent::getCurrentApprovalInstanceId, null);
            updateChain.eq(Agent::getId, resourceId);
            updateChain.update();
            cancelActiveRuns(resourceId, "Agent 已下线，待审批运行已取消");
            return null;
        });
    }

    @Override
    protected void removeResource(BigInteger resourceId) {
        agentBindingLockExecutor.execute(resourceId, () -> {
            cancelActiveRuns(resourceId, "Agent 已删除，待审批运行已取消");
            agentToolBindingService.remove(
                    QueryWrapper.create().eq(AgentToolBinding::getAgentId, resourceId));
            agentKnowledgeBindingService.remove(
                    QueryWrapper.create().eq(AgentKnowledgeBinding::getAgentId, resourceId));
            agentSkillBindingService.remove(
                    QueryWrapper.create().eq(AgentSkillBinding::getAgentId, resourceId));
            agentService.removeById(resourceId);
            return null;
        });
    }

    /**
     * 取消指定 Agent 的集群运行态和持久化待审批请求。
     *
     * @param resourceId Agent ID
     * @param reason 取消原因
     */
    private void cancelActiveRuns(BigInteger resourceId, String reason) {
        String agentId = resourceId.toString();
        Set<String> ownerNodeIds = agentRuntimeRouteRegistry.findOwnerNodesByAgent(agentId);
        agentHitlPendingService.cancelByAgentId(resourceId, reason);
        agentRunRegistry.cancelAgent(agentId);
        String currentNodeId = agentRuntimeRouteRegistry.currentNodeId();
        for (String ownerNodeId : ownerNodeIds) {
            if (ownerNodeId == null || ownerNodeId.isBlank() || ownerNodeId.equals(currentNodeId)) {
                continue;
            }
            agentRuntimeCommandProducer.sendCancelAgent(ownerNodeId, agentId, reason);
        }
    }

    @Override
    protected String resourceLabel() {
        return "Agent";
    }
}
