package tech.easyflow.ai.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tech.easyflow.ai.entity.Bot;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.service.AiResourceApprovalStateService;
import tech.easyflow.approval.entity.ApprovalInstance;
import tech.easyflow.approval.enums.ApprovalActionType;
import tech.easyflow.approval.enums.ApprovalInstanceStatus;
import tech.easyflow.approval.enums.ApprovalResourceType;
import tech.easyflow.approval.mapper.ApprovalInstanceMapper;

import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * AI 资源审批状态派生服务实现。
 */
@Service
public class AiResourceApprovalStateServiceImpl implements AiResourceApprovalStateService {

    private final ApprovalInstanceMapper approvalInstanceMapper;

    public AiResourceApprovalStateServiceImpl(ApprovalInstanceMapper approvalInstanceMapper) {
        this.approvalInstanceMapper = approvalInstanceMapper;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillWorkflowApprovalState(Workflow workflow) {
        fillWorkflowApprovalState(workflow == null ? List.of() : List.of(workflow));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillWorkflowApprovalState(Collection<Workflow> workflows) {
        fillApprovalState(
                workflows,
                ApprovalResourceType.WORKFLOW.getCode(),
                Workflow::getCurrentApprovalInstanceId,
                workflow -> PublishStatus.from(workflow.getPublishStatus()),
                Workflow::getPublishedSnapshotJson,
                Workflow::setApprovalPending,
                Workflow::setCurrentApprovalActionType,
                Workflow::setDisplayPublishStatus
        );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillKnowledgeApprovalState(DocumentCollection collection) {
        fillKnowledgeApprovalState(collection == null ? List.of() : List.of(collection));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillKnowledgeApprovalState(Collection<DocumentCollection> collections) {
        fillApprovalState(
                collections,
                ApprovalResourceType.KNOWLEDGE.getCode(),
                DocumentCollection::getCurrentApprovalInstanceId,
                collection -> PublishStatus.from(collection.getPublishStatus()),
                DocumentCollection::getPublishedSnapshotJson,
                DocumentCollection::setApprovalPending,
                DocumentCollection::setCurrentApprovalActionType,
                DocumentCollection::setDisplayPublishStatus
        );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillBotApprovalState(Bot bot) {
        fillBotApprovalState(bot == null ? List.of() : List.of(bot));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillBotApprovalState(Collection<Bot> bots) {
        fillApprovalState(
                bots,
                ApprovalResourceType.BOT.getCode(),
                Bot::getCurrentApprovalInstanceId,
                bot -> PublishStatus.from(bot.getPublishStatus()),
                Bot::getPublishedSnapshotJson,
                Bot::setApprovalPending,
                Bot::setCurrentApprovalActionType,
                Bot::setDisplayPublishStatus
        );
    }

    /**
     * 统一派生审批展示状态。
     *
     * @param resources 资源集合
     * @param resourceType 资源类型
     * @param instanceIdGetter 当前审批实例 ID 获取器
     * @param statusGetter 发布状态获取器
     * @param snapshotGetter 已发布快照获取器
     * @param pendingSetter 审批中标记写入器
     * @param actionSetter 当前审批动作写入器
     * @param displaySetter 展示状态写入器
     * @param <T> 资源类型
     */
    private <T> void fillApprovalState(Collection<T> resources,
                                       String resourceType,
                                       Function<T, BigInteger> instanceIdGetter,
                                       Function<T, PublishStatus> statusGetter,
                                       Function<T, Map<String, Object>> snapshotGetter,
                                       BiConsumer<T, Boolean> pendingSetter,
                                       BiConsumer<T, String> actionSetter,
                                       BiConsumer<T, String> displaySetter) {
        if (CollectionUtils.isEmpty(resources)) {
            return;
        }
        List<T> validResources = resources.stream().filter(Objects::nonNull).toList();
        if (validResources.isEmpty()) {
            return;
        }
        Map<BigInteger, ApprovalInstance> instanceMap = loadInstanceMap(validResources, instanceIdGetter);
        for (T resource : validResources) {
            PublishStatus currentStatus = statusGetter.apply(resource);
            BigInteger instanceId = instanceIdGetter.apply(resource);
            ApprovalInstance instance = instanceId == null ? null : instanceMap.get(instanceId);
            if (!isValidCurrentInstance(resourceType, instance)) {
                pendingSetter.accept(resource, false);
                actionSetter.accept(resource, null);
                displaySetter.accept(resource, resolveDisplayStatusWithoutActiveInstance(currentStatus, snapshotGetter.apply(resource)).getCode());
                continue;
            }

            ApprovalInstanceStatus instanceStatus = ApprovalInstanceStatus.from(instance.getStatus());
            if (instanceStatus.isFinished()) {
                pendingSetter.accept(resource, false);
                actionSetter.accept(resource, null);
                displaySetter.accept(resource, resolveDisplayStatusWithoutActiveInstance(currentStatus, snapshotGetter.apply(resource)).getCode());
                continue;
            }

            ApprovalActionType actionType = ApprovalActionType.from(instance.getActionType());
            pendingSetter.accept(resource, true);
            actionSetter.accept(resource, actionType.getCode());
            displaySetter.accept(resource, resolveDisplayStatusWithActiveInstance(currentStatus, actionType).getCode());
        }
    }

    /**
     * 批量加载当前审批实例。
     *
     * @param resources 资源集合
     * @param instanceIdGetter 当前审批实例 ID 获取器
     * @param <T> 资源类型
     * @return 审批实例映射
     */
    private <T> Map<BigInteger, ApprovalInstance> loadInstanceMap(Collection<T> resources,
                                                                  Function<T, BigInteger> instanceIdGetter) {
        Set<BigInteger> instanceIds = resources.stream()
                .map(instanceIdGetter)
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (instanceIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<ApprovalInstance> instances = approvalInstanceMapper.selectListByQuery(
                QueryWrapper.create().in(ApprovalInstance::getId, instanceIds)
        );
        return instances.stream().collect(Collectors.toMap(ApprovalInstance::getId, Function.identity()));
    }

    /**
     * 判断审批实例是否仍是当前资源的有效实例。
     *
     * @param resourceType 资源类型
     * @param instance 审批实例
     * @return 有效返回 true
     */
    private boolean isValidCurrentInstance(String resourceType, ApprovalInstance instance) {
        return instance != null && resourceType.equals(instance.getResourceType());
    }

    /**
     * 在没有活动审批实例时派生展示状态。
     *
     * @param currentStatus 当前真实状态
     * @param publishedSnapshot 已发布快照
     * @return 展示状态
     */
    private PublishStatus resolveDisplayStatusWithoutActiveInstance(PublishStatus currentStatus,
                                                                    Map<String, Object> publishedSnapshot) {
        // 读接口不再猜测或掩盖真实状态。若资源表已经落成 pending 但当前找不到有效审批实例，
        // 页面应直接看到真实状态，后续再由独立修复流程处理脏数据，而不是在展示层伪装成已发布。
        return currentStatus;
    }

    /**
     * 在存在活动审批实例时派生展示状态。
     *
     * @param currentStatus 当前真实状态
     * @param actionType 当前审批动作
     * @return 展示状态
     */
    private PublishStatus resolveDisplayStatusWithActiveInstance(PublishStatus currentStatus,
                                                                 ApprovalActionType actionType) {
        if (currentStatus == PublishStatus.PUBLISHED && actionType == ApprovalActionType.PUBLISH) {
            return PublishStatus.PUBLISH_PENDING;
        }
        if (currentStatus == PublishStatus.PUBLISH_PENDING
                || currentStatus == PublishStatus.OFFLINE_PENDING
                || currentStatus == PublishStatus.DELETE_PENDING) {
            return currentStatus;
        }
        return switch (actionType) {
            case PUBLISH -> PublishStatus.PUBLISH_PENDING;
            case OFFLINE -> PublishStatus.OFFLINE_PENDING;
            case DELETE -> PublishStatus.DELETE_PENDING;
        };
    }
}
