package tech.easyflow.approval.service;

import com.mybatisflex.core.paginate.Page;
import tech.easyflow.approval.entity.ApprovalFlowStep;
import tech.easyflow.approval.entity.ApprovalTask;
import tech.easyflow.approval.entity.vo.ApprovalAssigneeTargetVo;
import tech.easyflow.approval.entity.vo.ApprovalAssigneeOptionVo;
import tech.easyflow.approval.entity.vo.ApprovalFlowStepVo;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 审批对象服务。
 */
public interface ApprovalAssigneeService {

    /**
     * 规范化并校验审批步骤中的审批对象配置。
     *
     * @param step 步骤配置
     * @return 规范化后的步骤配置
     */
    ApprovalFlowStepVo normalizeStepAssignee(ApprovalFlowStepVo step);

    /**
     * 校验受发起人部门限制的步骤至少存在一个合法审批账号。
     *
     * @param steps 步骤配置
     * @param requiredDeptId 指定直属部门 ID；为空时校验任一有效部门
     */
    void validateRestrictedStepCandidates(List<ApprovalFlowStepVo> steps, BigInteger requiredDeptId);

    /**
     * 批量加载流程步骤的审批对象，关联记录缺失时兼容旧单值字段。
     *
     * @param steps 流程步骤
     * @return 步骤 ID 到审批对象列表的映射
     */
    Map<BigInteger, List<ApprovalAssigneeTargetVo>> loadStepAssigneeTargets(List<ApprovalFlowStep> steps);

    /**
     * 批量加载审批任务的审批对象，关联记录缺失时兼容旧单值字段。
     *
     * @param tasks 审批任务
     * @return 任务 ID 到审批对象列表的映射
     */
    Map<BigInteger, List<ApprovalAssigneeTargetVo>> loadTaskAssigneeTargets(List<ApprovalTask> tasks);

    /**
     * 保存流程步骤审批对象。
     *
     * @param stepId 流程步骤 ID
     * @param assigneeType 审批对象类型
     * @param targets 审批对象列表
     * @param operatorId 操作人 ID
     * @param now 操作时间
     */
    void saveStepAssigneeTargets(BigInteger stepId, String assigneeType, List<ApprovalAssigneeTargetVo> targets,
                                 BigInteger operatorId, Date now);

    /**
     * 删除指定流程步骤的审批对象。
     *
     * @param stepIds 流程步骤 ID
     */
    void deleteStepAssigneeTargets(List<BigInteger> stepIds);

    /**
     * 保存任务冻结的审批对象。
     *
     * @param taskId 审批任务 ID
     * @param assigneeType 审批对象类型
     * @param targets 审批对象列表
     * @param operatorId 操作人 ID
     * @param now 操作时间
     */
    void saveTaskAssigneeTargets(BigInteger taskId, String assigneeType, List<ApprovalAssigneeTargetVo> targets,
                                 BigInteger operatorId, Date now);

    /**
     * 查询可用角色选项。
     *
     * @return 角色选项
     */
    List<ApprovalAssigneeOptionVo> listRoleOptions();

    /**
     * 分页查询可用用户选项。
     *
     * @param keyword 关键词
     * @param pageNumber 页码
     * @param pageSize 每页数量
     * @return 用户选项分页
     */
    Page<ApprovalAssigneeOptionVo> pageAccountOptions(String keyword, Long pageNumber, Long pageSize);

    /**
     * 查询指定账号当前仍有效的角色 ID 集合。
     *
     * @param accountId 账号 ID
     * @return 角色 ID 集合
     */
    Set<BigInteger> getAvailableRoleIds(BigInteger accountId);

    /**
     * 判断当前账号是否命中审批任务。
     *
     * @param task 审批任务
     * @param operatorId 当前操作人
     * @param roleIds 当前操作人的有效角色集合
     * @return 是否命中
     */
    boolean canHandleTask(ApprovalTask task, BigInteger operatorId, Set<BigInteger> roleIds);

    /**
     * 查询当前账号命中的待审批实例 ID 集合。
     *
     * @param operatorId 当前操作人
     * @param roleIds 当前操作人的有效角色集合
     * @param instanceIds 可选的实例 ID 过滤条件
     * @return 命中的实例 ID 集合
     */
    Set<BigInteger> listPendingInstanceIds(BigInteger operatorId, Set<BigInteger> roleIds, List<BigInteger> instanceIds);
}
