
package tech.easyflow.ai.service.impl;
import com.alibaba.fastjson2.JSON;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.mapper.WorkflowMapper;
import tech.easyflow.ai.service.WorkflowService;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.context.ApplicationEventPublisher;
import tech.easyflow.ai.easyagentsflow.event.WorkflowDefinitionChangedEvent;
import tech.easyflow.ai.utils.RegexUtils;
import com.mybatisflex.core.query.QueryWrapper;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.ai.utils.CustomBeanUtils;

import java.math.BigInteger;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

/**
 * 服务层实现。
 *
 * @author michael
 * @since 2024-08-23
 */
@Service
public class WorkflowServiceImpl extends ServiceImpl<WorkflowMapper, Workflow> implements WorkflowService {

    @javax.annotation.Resource
    private ApplicationEventPublisher eventPublisher;

    /**
     * 根据别名或 id 查询详情
     */
    @Override
    public Workflow getDetail(String idOrAlias) {

        Workflow workflow = null;

        if (idOrAlias.matches(RegexUtils.ALL_NUMBER)) {
            workflow = getById(idOrAlias);
            if (workflow == null) {
                workflow = getByAlias(idOrAlias);
            }
        }

        if (workflow == null) {
            workflow = getByAlias(idOrAlias);
        }

        return workflow;
    }

    @Override
    public Workflow getByAlias(String idOrAlias) {

        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.eq("alias",idOrAlias);

        return getOne(queryWrapper);

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Workflow getPublishedDetail(String idOrAlias) {
        return toPublishedView(getDetail(idOrAlias));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Workflow getPublishedById(BigInteger id) {
        return toPublishedView(getById(id));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Workflow toPublishedView(Workflow workflow) {
        if (workflow == null) {
            return null;
        }
        Map<String, Object> snapshot = workflow.getPublishedSnapshotJson();
        if (snapshot == null || snapshot.isEmpty()) {
            return workflow;
        }
        Workflow published = JSON.parseObject(JSON.toJSONString(snapshot), Workflow.class);
        if (published == null) {
            return workflow;
        }
        published.setId(workflow.getId());
        published.setTenantId(workflow.getTenantId());
        published.setCategoryId(workflow.getCategoryId());
        published.setDeptId(workflow.getDeptId());
        published.setCreated(workflow.getCreated());
        published.setCreatedBy(workflow.getCreatedBy());
        published.setModified(workflow.getModified());
        published.setModifiedBy(workflow.getModifiedBy());
        published.setPublishStatus(workflow.getPublishStatus());
        published.setCurrentApprovalInstanceId(workflow.getCurrentApprovalInstanceId());
        published.setPublishedSnapshotJson(workflow.getPublishedSnapshotJson());
        published.setPublishedAt(workflow.getPublishedAt());
        published.setPublishedBy(workflow.getPublishedBy());
        if (published.getPublishStatus() == null) {
            published.setPublishStatus(PublishStatus.DRAFT.getCode());
        }
        return published;
    }


    @Override
    public boolean updateById(Workflow entity, boolean ignoreNulls) {
        Workflow workFlow = getById(entity.getId());
        if (workFlow == null) {
            throw new BusinessException("工作流不存在");
        }

        int nextRevision = workFlow.getRevision() == null ? 1 : workFlow.getRevision() + 1;
        CustomBeanUtils.copyPropertiesIgnoreNull(entity,workFlow);
        if (entity.getContent() != null) {
            workFlow.setRevision(nextRevision);
        }

        if ("".equals(workFlow.getAlias())){
            workFlow.setAlias(null);
        }


        boolean updated = super.updateById(workFlow,false);
        publishDefinitionChanged(updated, workFlow.getId());
        return updated;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean updateContentByRevision(
            BigInteger id,
            String content,
            Integer expectedRevision,
            Date modified,
            BigInteger modifiedBy
    ) {
        boolean updated = getMapper().updateContentByRevision(
                id,
                content,
                expectedRevision,
                modified,
                modifiedBy
        ) == 1;
        publishDefinitionChanged(updated, id);
        return updated;
    }

    /**
     * 删除工作流后使编译定义缓存失效。
     *
     * @param id 工作流 ID
     * @return 删除成功时为 true
     */
    @Override
    public boolean removeById(Serializable id) {
        boolean removed = super.removeById(id);
        if (removed && id != null && eventPublisher != null) {
            eventPublisher.publishEvent(new WorkflowDefinitionChangedEvent(String.valueOf(id)));
        }
        return removed;
    }

    /**
     * 批量删除工作流后使对应编译定义缓存失效。
     *
     * @param ids 工作流 ID 集合
     * @return 删除成功时为 true
     */
    @Override
    public boolean removeByIds(Collection<? extends Serializable> ids) {
        boolean removed = super.removeByIds(ids);
        if (removed && ids != null && eventPublisher != null) {
            for (Serializable id : ids) {
                if (id != null) {
                    eventPublisher.publishEvent(new WorkflowDefinitionChangedEvent(String.valueOf(id)));
                }
            }
        }
        return removed;
    }

    /**
     * 在工作流变更成功后发布定义失效事件。
     *
     * @param changed 是否已发生变更
     * @param workflowId 工作流 ID
     */
    private void publishDefinitionChanged(boolean changed, BigInteger workflowId) {
        if (changed && workflowId != null && eventPublisher != null) {
            eventPublisher.publishEvent(new WorkflowDefinitionChangedEvent(String.valueOf(workflowId)));
        }
    }

}
