package tech.easyflow.skill.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tech.easyflow.ai.enums.PublishStatus;
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 tech.easyflow.skill.entity.Skill;
import tech.easyflow.skill.service.SkillApprovalStateService;

import java.math.BigInteger;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Skill 审批展示态派生服务实现。
 */
@Service
public class SkillApprovalStateServiceImpl implements SkillApprovalStateService {

    private final ApprovalInstanceMapper approvalInstanceMapper;

    /**
     * 创建 Skill 审批展示态派生服务。
     *
     * @param approvalInstanceMapper 审批实例 Mapper
     */
    public SkillApprovalStateServiceImpl(ApprovalInstanceMapper approvalInstanceMapper) {
        this.approvalInstanceMapper = approvalInstanceMapper;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillSkillApprovalState(Skill skill) {
        fillSkillApprovalState(skill == null ? List.of() : List.of(skill));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void fillSkillApprovalState(Collection<Skill> skills) {
        if (CollectionUtils.isEmpty(skills)) {
            return;
        }
        List<Skill> validSkills = skills.stream().filter(Objects::nonNull).toList();
        if (validSkills.isEmpty()) {
            return;
        }
        Map<BigInteger, ApprovalInstance> instanceMap = loadInstanceMap(validSkills);
        for (Skill skill : validSkills) {
            fillOne(skill, instanceMap.get(skill.getCurrentApprovalInstanceId()));
        }
    }

    private void fillOne(Skill skill, ApprovalInstance instance) {
        PublishStatus currentStatus = PublishStatus.from(skill.getPublishStatus());
        if (!isValidCurrentInstance(instance)) {
            skill.setApprovalPending(false);
            skill.setCurrentApprovalActionType(null);
            skill.setDisplayPublishStatus(currentStatus.getCode());
            return;
        }
        ApprovalInstanceStatus instanceStatus = ApprovalInstanceStatus.from(instance.getStatus());
        if (instanceStatus.isFinished()) {
            skill.setApprovalPending(false);
            skill.setCurrentApprovalActionType(null);
            skill.setDisplayPublishStatus(currentStatus.getCode());
            return;
        }
        ApprovalActionType actionType = ApprovalActionType.from(instance.getActionType());
        skill.setApprovalPending(true);
        skill.setCurrentApprovalActionType(actionType.getCode());
        skill.setDisplayPublishStatus(resolveDisplayStatusWithActiveInstance(currentStatus, actionType).getCode());
    }

    private Map<BigInteger, ApprovalInstance> loadInstanceMap(Collection<Skill> skills) {
        Set<BigInteger> instanceIds = skills.stream()
                .map(Skill::getCurrentApprovalInstanceId)
                .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()));
    }

    private boolean isValidCurrentInstance(ApprovalInstance instance) {
        return instance != null && ApprovalResourceType.SKILL.getCode().equals(instance.getResourceType());
    }

    private PublishStatus resolveDisplayStatusWithActiveInstance(PublishStatus currentStatus,
                                                                 ApprovalActionType actionType) {
        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;
        };
    }
}
