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

import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.PluginItem;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PluginType;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.mapper.PluginItemMapper;
import tech.easyflow.ai.mapper.PluginMapper;
import tech.easyflow.ai.plugin.workflow.dependency.WorkflowPluginDependencyService;
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.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.List;

/**
 * 工作流插件绑定服务实现。
 */
@Service
public class WorkflowPluginBindingServiceImpl implements WorkflowPluginBindingService {

    private final PluginMapper pluginMapper;
    private final PluginItemMapper pluginItemMapper;
    private final WorkflowService workflowService;
    private final ResourceAccessService resourceAccessService;
    private final WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver;
    private final WorkflowPluginDependencyService workflowPluginDependencyService;

    public WorkflowPluginBindingServiceImpl(PluginMapper pluginMapper,
                                            PluginItemMapper pluginItemMapper,
                                            WorkflowService workflowService,
                                            ResourceAccessService resourceAccessService,
                                            WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver,
                                            WorkflowPluginDependencyService workflowPluginDependencyService) {
        this.pluginMapper = pluginMapper;
        this.pluginItemMapper = pluginItemMapper;
        this.workflowService = workflowService;
        this.resourceAccessService = resourceAccessService;
        this.workflowPluginSnapshotResolver = workflowPluginSnapshotResolver;
        this.workflowPluginDependencyService = workflowPluginDependencyService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Plugin saveWorkflowPlugin(Plugin plugin) {
        LoginAccount loginAccount = requireLogin();
        Workflow workflow = requirePublishedWorkflow(plugin.getWorkflowId(), "无权限绑定工作流");
        normalizeWorkflowPlugin(plugin, loginAccount);
        int insert = pluginMapper.insert(plugin);
        if (insert <= 0) {
            throw new BusinessException("保存失败");
        }
        PluginItem pluginItem = new PluginItem();
        pluginItem.setCreated(new Date());
        workflowPluginSnapshotResolver.syncPluginItemFromPublishedWorkflow(plugin, pluginItem, workflow.getId());
        if (pluginItemMapper.insert(pluginItem) <= 0) {
            throw new BusinessException("保存工作流插件工具失败");
        }
        return plugin;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWorkflowPlugin(Plugin plugin) {
        if (plugin.getId() == null) {
            throw new BusinessException("插件ID不能为空");
        }
        Plugin existed = pluginMapper.selectOneById(plugin.getId());
        if (existed == null) {
            throw new BusinessException("插件不存在");
        }
        if (PluginType.from(existed.getType()) != PluginType.WORKFLOW) {
            throw new BusinessException("暂不支持在现有 HTTP 插件与工作流插件之间切换类型");
        }

        Workflow workflow = requirePublishedWorkflow(plugin.getWorkflowId(), "无权限绑定工作流");
        if (workflowPluginDependencyService.containsPluginReferenceTransitivelyInPublishedSnapshot(workflow.getId(), existed.getId())) {
            throw new BusinessException("目标工作流已通过子流程或插件链路引用当前插件，无法形成递归绑定");
        }
        normalizeWorkflowPlugin(plugin, null);
        int updated = pluginMapper.update(plugin);
        if (updated <= 0) {
            throw new BusinessException("更新失败");
        }
        syncSinglePlugin(existed.getId(), workflow.getId());
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncByWorkflowId(BigInteger workflowId) {
        if (workflowId == null) {
            return;
        }
        QueryWrapper wrapper = QueryWrapper.create()
                .eq(Plugin::getWorkflowId, workflowId)
                .eq(Plugin::getType, PluginType.WORKFLOW.getCode());
        List<Plugin> plugins = pluginMapper.selectListByQuery(wrapper);
        for (Plugin plugin : plugins) {
            syncSinglePlugin(plugin.getId(), workflowId);
        }
    }

    private void syncSinglePlugin(BigInteger pluginId, BigInteger workflowId) {
        Plugin plugin = pluginMapper.selectOneById(pluginId);
        if (plugin == null) {
            return;
        }
        Workflow workflow = requirePublishedWorkflowForSync(workflowId);
        PluginItem pluginItem = getOrCreateSystemTool(pluginId);
        workflowPluginSnapshotResolver.syncPluginItemFromPublishedWorkflow(plugin, pluginItem, workflow.getId());
        if (pluginItem.getId() == null) {
            pluginItem.setCreated(new Date());
            if (pluginItemMapper.insert(pluginItem) <= 0) {
                throw new BusinessException("同步工作流插件工具失败");
            }
        } else if (pluginItemMapper.update(pluginItem) <= 0) {
            throw new BusinessException("同步工作流插件工具失败");
        }
    }

    private PluginItem getOrCreateSystemTool(BigInteger pluginId) {
        QueryWrapper wrapper = QueryWrapper.create().eq(PluginItem::getPluginId, pluginId);
        List<PluginItem> pluginItems = pluginItemMapper.selectListByQuery(wrapper);
        if (pluginItems == null || pluginItems.isEmpty()) {
            PluginItem pluginItem = new PluginItem();
            pluginItem.setPluginId(pluginId);
            return pluginItem;
        }
        PluginItem pluginItem = pluginItems.get(0);
        if (pluginItems.size() > 1) {
            for (int i = 1; i < pluginItems.size(); i++) {
                pluginItemMapper.deleteById(pluginItems.get(i).getId());
            }
        }
        return pluginItem;
    }

    private Workflow requirePublishedWorkflow(BigInteger workflowId, String denyMessage) {
        if (workflowId == null) {
            throw new BusinessException("请选择已发布工作流");
        }
        Workflow workflow = workflowService.getById(workflowId);
        if (workflow == null) {
            throw new BusinessException("工作流不存在");
        }
        resourceAccessService.assertAccess(CategoryResourceType.WORKFLOW, workflow, ResourceAction.USE, denyMessage);
        PublishStatus publishStatus = PublishStatus.from(workflow.getPublishStatus());
        if (publishStatus != PublishStatus.PUBLISHED) {
            throw new BusinessException("仅已发布工作流可被封装为插件");
        }
        if (workflow.getPublishedSnapshotJson() == null || workflow.getPublishedSnapshotJson().isEmpty()) {
            throw new BusinessException("目标工作流缺少已发布快照");
        }
        workflowPluginSnapshotResolver.assertSupportedForWorkflowPlugin(workflowService.toPublishedView(workflow));
        return workflow;
    }

    private Workflow requirePublishedWorkflowForSync(BigInteger workflowId) {
        if (workflowId == null) {
            throw new BusinessException("目标工作流不存在");
        }
        Workflow workflow = workflowService.getById(workflowId);
        if (workflow == null) {
            throw new BusinessException("目标工作流不存在");
        }
        PublishStatus publishStatus = PublishStatus.from(workflow.getPublishStatus());
        if (publishStatus != PublishStatus.PUBLISHED) {
            throw new BusinessException("仅已发布工作流可同步到工作流插件");
        }
        if (workflow.getPublishedSnapshotJson() == null || workflow.getPublishedSnapshotJson().isEmpty()) {
            throw new BusinessException("目标工作流缺少已发布快照");
        }
        workflowPluginSnapshotResolver.assertSupportedForWorkflowPlugin(workflowService.toPublishedView(workflow));
        return workflow;
    }

    private void normalizeWorkflowPlugin(Plugin plugin, LoginAccount loginAccount) {
        plugin.setType(PluginType.WORKFLOW.getCode());
        plugin.setBaseUrl(null);
        plugin.setAuthType(null);
        plugin.setPosition(null);
        plugin.setHeaders(null);
        plugin.setTokenKey(null);
        plugin.setTokenValue(null);
        if (plugin.getCreated() == null) {
            plugin.setCreated(new Date());
        }
        if (loginAccount != null) {
            plugin.setCreatedBy(loginAccount.getId().longValue());
            plugin.setDeptId(loginAccount.getDeptId() == null ? null : loginAccount.getDeptId().longValue());
            plugin.setTenantId(loginAccount.getTenantId() == null ? null : loginAccount.getTenantId().longValue());
        }
        if (!StringUtils.hasText(plugin.getAlias())) {
            plugin.setAlias(null);
        }
    }

    private LoginAccount requireLogin() {
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        if (loginAccount == null || loginAccount.getId() == null) {
            throw new BusinessException("当前未登录");
        }
        return loginAccount;
    }
}
