package tech.easyflow.approval.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.util.SearchKeywordUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.approval.entity.ApprovalFlowStep;
import tech.easyflow.approval.entity.ApprovalInstance;
import tech.easyflow.approval.entity.ApprovalLog;
import tech.easyflow.approval.entity.ApprovalTask;
import tech.easyflow.approval.entity.vo.ApprovalAssigneeTargetVo;
import tech.easyflow.approval.entity.vo.ApprovalInstanceDetailVo;
import tech.easyflow.approval.entity.vo.ApprovalInstancePageVo;
import tech.easyflow.approval.entity.vo.ApprovalFlowStepVo;
import tech.easyflow.approval.entity.vo.ApprovalLogVo;
import tech.easyflow.approval.entity.vo.ApprovalTaskVo;
import tech.easyflow.approval.enums.ApprovalActionType;
import tech.easyflow.approval.enums.ApprovalEventType;
import tech.easyflow.approval.enums.ApprovalInstanceStatus;
import tech.easyflow.approval.enums.ApprovalResourceType;
import tech.easyflow.approval.enums.ApprovalTaskStatus;
import tech.easyflow.approval.mapper.ApprovalFlowStepMapper;
import tech.easyflow.approval.mapper.ApprovalInstanceMapper;
import tech.easyflow.approval.mapper.ApprovalLogMapper;
import tech.easyflow.approval.mapper.ApprovalTaskMapper;
import tech.easyflow.approval.service.ApprovalActionFacade;
import tech.easyflow.approval.service.ApprovalAssigneeService;
import tech.easyflow.approval.service.ApprovalQueryService;
import tech.easyflow.system.entity.SysAccount;
import tech.easyflow.system.service.CategoryPermissionService;
import tech.easyflow.system.service.SysAccountService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 审批查询服务实现。
 */
@Service
public class ApprovalQueryServiceImpl implements ApprovalQueryService {

    @Resource
    private ApprovalInstanceMapper approvalInstanceMapper;

    @Resource
    private ApprovalTaskMapper approvalTaskMapper;

    @Resource
    private ApprovalLogMapper approvalLogMapper;

    @Resource
    private ApprovalFlowStepMapper approvalFlowStepMapper;

    @Resource
    private ApprovalAssigneeService approvalAssigneeService;

    @Resource
    private ApprovalActionFacade approvalActionFacade;

    @Resource
    private CategoryPermissionService categoryPermissionService;

    @Resource
    private SysAccountService sysAccountService;

    /**
     * {@inheritDoc}
     */
    @Override
    public Page<ApprovalInstancePageVo> pendingPage(String resourceType, String actionType, String keyword,
                                                    Long pageNumber, Long pageSize) {
        LoginAccount account = requireLoginAccount();
        Set<BigInteger> roleIds = approvalAssigneeService.getAvailableRoleIds(account.getId());
        Set<BigInteger> instanceIds = approvalAssigneeService.listPendingInstanceIds(account.getId(), roleIds, null);
        if (CollectionUtil.isEmpty(instanceIds)) {
            return new Page<>(List.of(), safePageNumber(pageNumber), safePageSize(pageSize), 0L);
        }
        QueryWrapper queryWrapper = buildBaseQuery(resourceType, actionType, keyword);
        queryWrapper.eq(ApprovalInstance::getTenantId, account.getTenantId());
        queryWrapper.in(ApprovalInstance::getId, instanceIds);
        queryWrapper.in(ApprovalInstance::getStatus, List.of(
                ApprovalInstanceStatus.PENDING.getCode(),
                ApprovalInstanceStatus.PROCESSING.getCode()));
        queryWrapper.orderBy("submitted_at desc, id desc");
        return mapPage(queryWrapper, safePageNumber(pageNumber), safePageSize(pageSize), true, account, roleIds);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Page<ApprovalInstancePageVo> processedPage(String resourceType, String actionType, String keyword,
                                                      Long pageNumber, Long pageSize) {
        LoginAccount account = requireLoginAccount();
        QueryWrapper actedTaskWrapper = QueryWrapper.create()
                .eq(ApprovalTask::getActedBy, account.getId())
                .in(ApprovalTask::getStatus, List.of(
                        ApprovalTaskStatus.APPROVED.getCode(),
                        ApprovalTaskStatus.REJECTED.getCode(),
                        ApprovalTaskStatus.REVOKED.getCode()));
        List<BigInteger> instanceIds = approvalTaskMapper.selectListByQuery(actedTaskWrapper).stream()
                .map(ApprovalTask::getInstanceId)
                .distinct()
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(instanceIds)) {
            return new Page<>(List.of(), safePageNumber(pageNumber), safePageSize(pageSize), 0L);
        }
        QueryWrapper queryWrapper = buildBaseQuery(resourceType, actionType, keyword);
        queryWrapper.eq(ApprovalInstance::getTenantId, account.getTenantId());
        queryWrapper.in(ApprovalInstance::getId, instanceIds);
        queryWrapper.orderBy("finished_at desc, id desc");
        return mapPage(queryWrapper, safePageNumber(pageNumber), safePageSize(pageSize), false, account, Set.of());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Page<ApprovalInstancePageVo> initiatedPage(String resourceType, String actionType, String keyword,
                                                      Long pageNumber, Long pageSize) {
        LoginAccount account = requireLoginAccount();
        QueryWrapper queryWrapper = buildBaseQuery(resourceType, actionType, keyword);
        queryWrapper.eq(ApprovalInstance::getTenantId, account.getTenantId());
        queryWrapper.eq(ApprovalInstance::getApplicantId, account.getId());
        queryWrapper.orderBy("submitted_at desc, id desc");
        return mapPage(queryWrapper, safePageNumber(pageNumber), safePageSize(pageSize), false, account, Set.of());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ApprovalInstanceDetailVo detail(BigInteger instanceId) {
        LoginAccount account = requireLoginAccount();
        ApprovalInstance instance = approvalInstanceMapper.selectOneByQuery(QueryWrapper.create()
                .eq(ApprovalInstance::getId, instanceId)
                .eq(ApprovalInstance::getTenantId, account.getTenantId()));
        if (instance == null || !Objects.equals(account.getTenantId(), instance.getTenantId())) {
            throw new BusinessException(404, 404, "审批实例不存在");
        }
        List<ApprovalTask> tasks = approvalTaskMapper.selectListByQuery(
                QueryWrapper.create().eq(ApprovalTask::getInstanceId, instanceId));
        Set<BigInteger> roleIds = approvalAssigneeService.getAvailableRoleIds(account.getId());
        assertDetailAccess(instance, tasks, account, roleIds);

        ApprovalInstanceDetailVo detail = new ApprovalInstanceDetailVo();
        detail.setId(instance.getId());
        detail.setFlowId(instance.getFlowId());
        detail.setFlowVersion(instance.getFlowVersion());
        detail.setResourceType(instance.getResourceType());
        detail.setResourceId(instance.getResourceId());
        detail.setActionType(instance.getActionType());
        detail.setStatus(instance.getStatus());
        detail.setCurrentStepNo(instance.getCurrentStepNo());
        detail.setSummary(instance.getSummary());
        detail.setApplicationReason(instance.getApplicationReason());
        detail.setApplicantId(instance.getApplicantId());
        detail.setSubmittedAt(instance.getSubmittedAt());
        detail.setFinishedAt(instance.getFinishedAt());
        detail.setSnapshotJson(instance.getSnapshotJson());

        List<ApprovalLog> logs = approvalLogMapper.selectListByQuery(
                QueryWrapper.create().eq(ApprovalLog::getInstanceId, instanceId));
        Map<Integer, ApprovalFlowStepVo> frozenStepMap = resolveFrozenStepMap(instance);
        Map<BigInteger, List<ApprovalAssigneeTargetVo>> taskTargetMap =
                approvalAssigneeService.loadTaskAssigneeTargets(tasks);
        Map<BigInteger, SysAccount> accountMap = loadAccountMap(instance, tasks, logs, account.getTenantId());
        detail.setApplicantName(resolveAccountName(accountMap.get(instance.getApplicantId())));
        detail.setApplicantAccount(resolveAccountLoginName(accountMap.get(instance.getApplicantId())));

        detail.setTasks(tasks.stream()
                .sorted(Comparator.comparing(ApprovalTask::getStepNo))
                .map(item -> {
                    ApprovalTaskVo taskVo = new ApprovalTaskVo();
                    taskVo.setId(item.getId());
                    taskVo.setStepNo(item.getStepNo());
                    taskVo.setStepName(resolveStepName(frozenStepMap, item.getStepNo()));
                    taskVo.setApplicationReason(instance.getApplicationReason());
                    taskVo.setStatus(item.getStatus());
                    taskVo.setAssigneeRoleCode(item.getAssigneeRoleCode());
                    taskVo.setAssigneeType(item.getAssigneeType());
                    taskVo.setAssigneeTargetId(item.getAssigneeTargetId());
                    taskVo.setAssigneeTargetCode(item.getAssigneeTargetCode());
                    taskVo.setAssigneeTargetName(item.getAssigneeTargetName());
                    taskVo.setAssigneeTargets(taskTargetMap.getOrDefault(item.getId(), List.of()));
                    taskVo.setActedBy(item.getActedBy());
                    taskVo.setActedByName(resolveAccountName(accountMap.get(item.getActedBy())));
                    taskVo.setActedAt(item.getActedAt());
                    taskVo.setComment(item.getComment());
                    return taskVo;
                })
                .collect(Collectors.toList()));

        detail.setLogs(logs.stream()
                .sorted(Comparator.comparing(ApprovalLog::getCreated))
                .map(item -> {
                    ApprovalLogVo logVo = new ApprovalLogVo();
                    logVo.setId(item.getId());
                    logVo.setEventType(item.getEventType());
                    if (ApprovalEventType.SUBMITTED.getCode().equals(item.getEventType())) {
                        logVo.setApplicationReason(instance.getApplicationReason());
                    }
                    logVo.setOperatorId(item.getOperatorId());
                    logVo.setOperatorAccount(resolveAccountLoginName(accountMap.get(item.getOperatorId())));
                    logVo.setOperatorName(resolveAccountName(accountMap.get(item.getOperatorId())));
                    logVo.setCreated(item.getCreated());
                    logVo.setPayloadJson(item.getPayloadJson());
                    return logVo;
                })
                .collect(Collectors.toList()));

        boolean active = !ApprovalInstanceStatus.from(instance.getStatus()).isFinished();
        boolean canReview = active
                && tasks.stream().anyMatch(item -> item.getStepNo().equals(instance.getCurrentStepNo())
                && ApprovalTaskStatus.PENDING.getCode().equals(item.getStatus())
                && approvalAssigneeService.canHandleTask(item, account.getId(), roleIds));
        detail.setCanApprove(canReview);
        detail.setCanReject(canReview);
        detail.setCanRevoke(active && Objects.equals(account.getId(), instance.getApplicantId()));
        return detail;
    }

    /**
     * 批量加载审批详情里涉及到的账号信息。
     *
     * @param instance 审批实例
     * @param tasks 审批任务列表
     * @param logs 审批日志列表
     * @param tenantId 当前租户 ID
     * @return 账号 ID 到账号实体的映射
     */
    private Map<BigInteger, SysAccount> loadAccountMap(ApprovalInstance instance, List<ApprovalTask> tasks,
                                                       List<ApprovalLog> logs, BigInteger tenantId) {
        Set<BigInteger> accountIds = new HashSet<>();
        if (instance.getApplicantId() != null) {
            accountIds.add(instance.getApplicantId());
        }
        tasks.stream()
                .map(ApprovalTask::getActedBy)
                .filter(id -> id != null)
                .forEach(accountIds::add);
        logs.stream()
                .map(ApprovalLog::getOperatorId)
                .filter(id -> id != null)
                .forEach(accountIds::add);
        if (CollectionUtil.isEmpty(accountIds)) {
            return Map.of();
        }
        return sysAccountService.list(QueryWrapper.create()
                        .in(SysAccount::getId, accountIds)
                        .eq(SysAccount::getTenantId, tenantId)).stream()
                .collect(Collectors.toMap(
                        SysAccount::getId,
                        account -> account,
                        (left, right) -> left,
                        LinkedHashMap::new));
    }

    /**
     * 解析账号展示名称，优先昵称，其次登录名。
     *
     * @param account 账号实体
     * @return 展示名称
     */
    private String resolveAccountName(SysAccount account) {
        if (account == null) {
            return null;
        }
        if (StringUtils.hasText(account.getNickname())) {
            return account.getNickname().trim();
        }
        if (StringUtils.hasText(account.getLoginName())) {
            return account.getLoginName().trim();
        }
        return null;
    }

    /**
     * 解析账号登录名。
     *
     * @param account 账号实体
     * @return 登录账号
     */
    private String resolveAccountLoginName(SysAccount account) {
        if (account == null || !StringUtils.hasText(account.getLoginName())) {
            return null;
        }
        return account.getLoginName().trim();
    }

    private QueryWrapper buildBaseQuery(String resourceType, String actionType, String keyword) {
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (StringUtils.hasText(resourceType)) {
            queryWrapper.eq(ApprovalInstance::getResourceType, ApprovalResourceType.from(resourceType).getCode());
        }
        if (StringUtils.hasText(actionType)) {
            queryWrapper.eq(ApprovalInstance::getActionType, ApprovalActionType.from(actionType).getCode());
        }
        if (StringUtils.hasText(keyword)) {
            queryWrapper.and("summary LIKE ?", SearchKeywordUtil.literalContainsPattern(keyword));
        }
        return queryWrapper;
    }

    private Page<ApprovalInstancePageVo> mapPage(QueryWrapper queryWrapper, long pageNumber, long pageSize,
                                                 boolean pendingMode, LoginAccount account, Set<BigInteger> roleIds) {
        Page<ApprovalInstance> page = approvalInstanceMapper.paginate(pageNumber, pageSize, queryWrapper);
        List<ApprovalInstance> records = page.getRecords();
        Map<BigInteger, SysAccount> applicantAccountMap = loadApplicantAccountMap(records, account.getTenantId());
        Set<BigInteger> pendingTaskInstanceIds = pendingMode
                ? approvalAssigneeService.listPendingInstanceIds(account.getId(), roleIds,
                records.stream().map(ApprovalInstance::getId).collect(Collectors.toList()))
                : Set.of();

        List<ApprovalInstancePageVo> result = new ArrayList<>();
        for (ApprovalInstance record : records) {
            ApprovalInstancePageVo item = new ApprovalInstancePageVo();
            item.setId(record.getId());
            item.setResourceType(record.getResourceType());
            item.setResourceId(record.getResourceId());
            item.setActionType(record.getActionType());
            item.setStatus(record.getStatus());
            item.setCurrentStepNo(record.getCurrentStepNo());
            item.setCurrentStepName(resolveCurrentStepName(record));
            item.setSummary(record.getSummary());
            item.setApplicationReason(record.getApplicationReason());
            item.setApplicantId(record.getApplicantId());
            SysAccount applicantAccount = applicantAccountMap.get(record.getApplicantId());
            item.setApplicantName(resolveAccountName(applicantAccount));
            item.setApplicantAccount(resolveAccountLoginName(applicantAccount));
            item.setSubmittedAt(record.getSubmittedAt());
            item.setFinishedAt(record.getFinishedAt());
            boolean active = !ApprovalInstanceStatus.from(record.getStatus()).isFinished();
            boolean canReview = pendingMode
                    && pendingTaskInstanceIds.contains(record.getId())
                    && active;
            item.setCanApprove(canReview);
            item.setCanReject(canReview);
            item.setCanRevoke(active && Objects.equals(account.getId(), record.getApplicantId()));
            result.add(item);
        }

        Page<ApprovalInstancePageVo> voPage = new Page<>(pageNumber, pageSize, page.getTotalRow());
        voPage.setRecords(result);
        return voPage;
    }

    /**
     * 批量加载分页记录中的申请人账号，避免列表逐行查询。
     *
     * @param records 审批实例分页记录
     * @param tenantId 当前租户 ID
     * @return 申请人 ID 到账号实体的映射
     */
    private Map<BigInteger, SysAccount> loadApplicantAccountMap(List<ApprovalInstance> records, BigInteger tenantId) {
        Set<BigInteger> applicantIds = records.stream()
                .map(ApprovalInstance::getApplicantId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        if (CollectionUtil.isEmpty(applicantIds)) {
            return Map.of();
        }
        return sysAccountService.list(QueryWrapper.create()
                        .in(SysAccount::getId, applicantIds)
                        .eq(SysAccount::getTenantId, tenantId)).stream()
                .collect(Collectors.toMap(
                        SysAccount::getId,
                        account -> account,
                        (left, right) -> left,
                        LinkedHashMap::new));
    }

    private long safePageNumber(Long pageNumber) {
        return pageNumber == null || pageNumber < 1 ? 1L : pageNumber;
    }

    private long safePageSize(Long pageSize) {
        return pageSize == null || pageSize < 1 ? 10L : pageSize;
    }

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

    /**
     * 校验审批详情的主体权限。
     *
     * @param instance 审批实例
     * @param tasks 审批任务
     * @param account 当前账号
     * @param roleIds 当前账号的有效角色 ID
     * @throws BusinessException 当前用户不是申请人、处理人、同租户超管或资源授权者时抛出
     */
    private void assertDetailAccess(ApprovalInstance instance,
                                    List<ApprovalTask> tasks,
                                    LoginAccount account,
                                    Set<BigInteger> roleIds) {
        if (account.getId().equals(instance.getApplicantId())
                || categoryPermissionService.isSuperAdmin(account)) {
            return;
        }
        boolean taskParticipant = tasks.stream().anyMatch(task -> account.getId().equals(task.getActedBy())
                || ApprovalTaskStatus.PENDING.getCode().equals(task.getStatus())
                && approvalAssigneeService.canHandleTask(task, account.getId(), roleIds));
        if (taskParticipant
                || approvalActionFacade.canAccessApprovalDetail(instance.getResourceType(), instance.getResourceId())) {
            return;
        }
        throw new BusinessException(403, 403, "无权限查看该审批实例");
    }

    private String resolveCurrentStepName(ApprovalInstance instance) {
        Map<Integer, ApprovalFlowStepVo> stepMap = resolveFrozenStepMap(instance);
        return resolveStepName(stepMap, instance.getCurrentStepNo());
    }

    private String resolveStepName(Map<Integer, ApprovalFlowStepVo> stepMap, Integer stepNo) {
        ApprovalFlowStepVo step = stepMap.get(stepNo);
        return step == null ? null : step.getStepName();
    }

    private Map<Integer, ApprovalFlowStepVo> resolveFrozenStepMap(ApprovalInstance instance) {
        Map<Integer, ApprovalFlowStepVo> result = new LinkedHashMap<>();
        Object steps = instance.getSnapshotJson() == null ? null : instance.getSnapshotJson().get("steps");
        if (steps instanceof List<?> frozenSteps) {
            for (Object item : frozenSteps) {
                if (!(item instanceof Map<?, ?> map)) {
                    continue;
                }
                Object stepNo = map.get("stepNo");
                Object stepName = map.get("stepName");
                if (!(stepNo instanceof Number) || stepName == null) {
                    continue;
                }
                ApprovalFlowStepVo stepVo = new ApprovalFlowStepVo();
                stepVo.setStepNo(((Number) stepNo).intValue());
                stepVo.setStepName(String.valueOf(stepName));
                Object assigneeType = map.get("assigneeType");
                Object assigneeTargetId = map.get("assigneeTargetId");
                Object assigneeTargetCode = map.get("assigneeTargetCode");
                Object assigneeTargetName = map.get("assigneeTargetName");
                if (assigneeType != null) {
                    stepVo.setAssigneeType(String.valueOf(assigneeType));
                }
                if (assigneeTargetId instanceof Number number) {
                    stepVo.setAssigneeTargetId(BigInteger.valueOf(number.longValue()));
                } else if (assigneeTargetId instanceof String string && StringUtils.hasText(string)) {
                    stepVo.setAssigneeTargetId(new BigInteger(string));
                }
                if (assigneeTargetCode != null) {
                    stepVo.setAssigneeTargetCode(String.valueOf(assigneeTargetCode));
                }
                if (assigneeTargetName != null) {
                    stepVo.setAssigneeTargetName(String.valueOf(assigneeTargetName));
                }
                stepVo.setAssigneeTargets(parseAssigneeTargets(map.get("assigneeTargets")));
                if (stepVo.getAssigneeTargets().isEmpty() && stepVo.getAssigneeTargetId() != null) {
                    stepVo.setAssigneeTargets(List.of(legacyTarget(stepVo)));
                }
                result.put(stepVo.getStepNo(), stepVo);
            }
        }
        if (!result.isEmpty() && result.values().stream().allMatch(item ->
                item.getAssigneeType() != null && CollectionUtil.isNotEmpty(item.getAssigneeTargets()))) {
            return result;
        }
        List<ApprovalFlowStep> storedSteps = approvalFlowStepMapper.selectListByQuery(
                QueryWrapper.create().eq(ApprovalFlowStep::getFlowId, instance.getFlowId()));
        Map<BigInteger, List<ApprovalAssigneeTargetVo>> targetMap =
                approvalAssigneeService.loadStepAssigneeTargets(storedSteps);
        for (ApprovalFlowStep step : storedSteps) {
            ApprovalFlowStepVo stepVo = result.computeIfAbsent(step.getStepNo(), key -> {
                ApprovalFlowStepVo value = new ApprovalFlowStepVo();
                value.setStepNo(step.getStepNo());
                return value;
            });
            if (!StringUtils.hasText(stepVo.getStepName())) {
                stepVo.setStepName(step.getStepName());
            }
            if (!StringUtils.hasText(stepVo.getAssigneeType())) {
                stepVo.setAssigneeType(step.getAssigneeType());
            }
            if (stepVo.getAssigneeTargetId() == null) {
                stepVo.setAssigneeTargetId(step.getAssigneeTargetId());
            }
            if (!StringUtils.hasText(stepVo.getAssigneeTargetCode())) {
                stepVo.setAssigneeTargetCode(step.getAssigneeTargetCode());
            }
            if (!StringUtils.hasText(stepVo.getAssigneeTargetName())) {
                stepVo.setAssigneeTargetName(step.getAssigneeTargetName());
            }
            if (CollectionUtil.isEmpty(stepVo.getAssigneeTargets())) {
                stepVo.setAssigneeTargets(targetMap.getOrDefault(step.getId(), List.of()));
            }
        }
        return result;
    }

    /**
     * 从冻结快照中解析审批对象列表。
     *
     * @param value 快照字段
     * @return 审批对象列表
     */
    private List<ApprovalAssigneeTargetVo> parseAssigneeTargets(Object value) {
        if (!(value instanceof List<?> values)) {
            return List.of();
        }
        List<ApprovalAssigneeTargetVo> result = new ArrayList<>();
        for (Object item : values) {
            if (!(item instanceof Map<?, ?> map)) {
                continue;
            }
            BigInteger targetId = parseTargetId(map.get("targetId"));
            if (targetId == null) {
                continue;
            }
            ApprovalAssigneeTargetVo target = new ApprovalAssigneeTargetVo();
            target.setTargetId(targetId);
            target.setTargetCode(map.get("targetCode") == null ? null : String.valueOf(map.get("targetCode")));
            target.setTargetName(map.get("targetName") == null ? null : String.valueOf(map.get("targetName")));
            Object includeChildren = map.get("includeChildren");
            target.setIncludeChildren(includeChildren instanceof Number number && number.intValue() == 1
                    || Boolean.TRUE.equals(includeChildren) ? 1 : 0);
            result.add(target);
        }
        return result;
    }

    /**
     * 解析快照中的对象 ID。
     *
     * @param value 快照值
     * @return 对象 ID
     */
    private BigInteger parseTargetId(Object value) {
        if (value instanceof BigInteger bigInteger) {
            return bigInteger;
        }
        if (value instanceof Number number) {
            return new BigInteger(number.toString());
        }
        if (value instanceof String string && StringUtils.hasText(string)) {
            return new BigInteger(string);
        }
        return null;
    }

    /**
     * 将旧单值步骤转换为单元素审批对象。
     *
     * @param step 旧步骤
     * @return 审批对象
     */
    private ApprovalAssigneeTargetVo legacyTarget(ApprovalFlowStepVo step) {
        ApprovalAssigneeTargetVo target = new ApprovalAssigneeTargetVo();
        target.setTargetId(step.getAssigneeTargetId());
        target.setTargetCode(step.getAssigneeTargetCode());
        target.setTargetName(step.getAssigneeTargetName());
        target.setIncludeChildren(0);
        return target;
    }
}
