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.entity.Agent;
import tech.easyflow.agent.entity.AgentKnowledgeBinding;
import tech.easyflow.agent.entity.AgentToolBinding;
import tech.easyflow.agent.service.AgentKnowledgeBindingService;
import tech.easyflow.agent.service.AgentService;
import tech.easyflow.agent.service.AgentToolBindingService;
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;

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

    private final AgentService agentService;
    private final AgentToolBindingService agentToolBindingService;
    private final AgentKnowledgeBindingService agentKnowledgeBindingService;
    private final ResourceAccessService resourceAccessService;

    /**
     * 创建 Agent 审批资源处理器。
     *
     * @param approvalInstanceService 审批实例服务
     * @param objectMapper JSON 映射器
     * @param agentService Agent 服务
     * @param agentToolBindingService Agent 工具绑定服务
     * @param agentKnowledgeBindingService Agent 知识库绑定服务
     * @param resourceAccessService 资源访问服务
     */
    public AgentApprovalSubjectHandler(ApprovalInstanceService approvalInstanceService,
                                       ObjectMapper objectMapper,
                                       AgentService agentService,
                                       AgentToolBindingService agentToolBindingService,
                                       AgentKnowledgeBindingService agentKnowledgeBindingService,
                                       ResourceAccessService resourceAccessService) {
        super(approvalInstanceService, objectMapper);
        this.agentService = agentService;
        this.agentToolBindingService = agentToolBindingService;
        this.agentKnowledgeBindingService = agentKnowledgeBindingService;
        this.resourceAccessService = resourceAccessService;
    }

    /**
     * {@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) {
        // 生命周期操作仅更新状态字段，避免实体默认空配置覆盖 Agent 草稿配置。
        UpdateChain<Agent> updateChain = agentService.updateChain();
        updateChain.set(Agent::getPublishStatus, publishStatus.getCode());
        updateChain.set(Agent::getCurrentApprovalInstanceId, currentApprovalInstanceId);
        updateChain.eq(Agent::getId, resourceId);
        updateChain.update();
    }

    @Override
    protected void publishResource(BigInteger resourceId, Map<String, Object> resourceSnapshot, BigInteger operatorId) {
        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();
    }

    @Override
    protected void markResourceOffline(BigInteger 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();
    }

    @Override
    protected void removeResource(BigInteger resourceId) {
        agentService.removeById(resourceId);
    }

    @Override
    protected void beforeRemove(BigInteger resourceId) {
        agentToolBindingService.remove(QueryWrapper.create().eq(AgentToolBinding::getAgentId, resourceId));
        agentKnowledgeBindingService.remove(QueryWrapper.create().eq(AgentKnowledgeBinding::getAgentId, resourceId));
    }

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