package com.njcn.rdms.module.project.service.project.execution;

import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.project.constant.ObjectActivityConstants;
import com.njcn.rdms.module.project.constant.ProjectExecutionConstants;
import com.njcn.rdms.module.project.controller.admin.project.execution.vo.execution.ProjectExecutionLifecycleActionRespVO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusTransitionDO;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusTransitionMapper;
import com.njcn.rdms.module.project.enums.ErrorCodeConstants;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 执行状态生命周期视图。
 * <p>
 * {@code getLifecycle} 返回的 {@code availableActions} 按 spec §7.1 实现约束过滤：
 * <ol>
 *   <li>剔除系统级动作 {@code auto_start}（不出现在 UI 按钮）。</li>
 *   <li>对 owner-only 状态推进动作（complete / cancel / pause / resume），按 {@code execution.ownerId == currentUserId} 字段硬卡过滤，
 *       与 {@link ProjectExecutionServiceImpl} 中 {@code validateOwnerForAction} 同款判定。</li>
 *   <li>对 {@code complete} 动作叠加进度过滤，执行进度未达到 100 时不下发完成按钮。</li>
 *   <li>对 {@code complete} 动作再叠加根任务完成态过滤：要求该执行下"参与聚合的根任务"全部为 completed
 *       才下发；筛选口径与进度聚合同源（execution_id + parent_task_id IS NULL + excludedStatusCodes），
 *       空集（无参与聚合的根任务）视为"未全部完成"，不下发完成按钮，避免任务仍在进行中时执行被闭环。</li>
 * </ol>
 * 非状态动作（delete / change-owner / update / assignee）的权限码 / 字段过滤未纳入本字段，
 * 前端按各动作对应权限码与 owner 字段独立判断（spec §6.5 允许条件矩阵）；
 * 全量化纳入 {@code availableActions} 留待后续阶段统一改造。
 */
@Service
public class ProjectExecutionStatusViewService {

    /**
     * 状态推进动作中要求 owner-only 字段硬卡的集合，与 ProjectExecutionServiceImpl#validateOwnerForAction 一致。
     */
    private static final Set<String> OWNER_ONLY_ACTIONS = Set.of("complete", "cancel", "pause", "resume");
    private static final String ACTION_COMPLETE = "complete";
    private static final BigDecimal COMPLETE_PROGRESS_THRESHOLD = BigDecimal.valueOf(100);

    @Resource
    private ObjectStatusModelMapper objectStatusModelMapper;
    @Resource
    private ObjectStatusTransitionMapper objectStatusTransitionMapper;

    public ProjectExecutionLifecycleView getLifecycle(String statusCode, Long ownerId, BigDecimal progressRate,
                                                      boolean rootTasksAllCompleted) {
        ObjectStatusModelDO statusModel = objectStatusModelMapper
                .selectByObjectTypeAndStatusCodeEnabled(ProjectExecutionConstants.OBJECT_TYPE, statusCode);
        if (statusModel == null) {
            throw exception(ErrorCodeConstants.PROJECT_EXECUTION_STATUS_MODEL_NOT_EXISTS_OR_DISABLED);
        }
        return new ProjectExecutionLifecycleView(
                statusModel.getStatusName(),
                statusModel.getTerminalFlag(),
                statusModel.getAllowEdit(),
                buildAvailableActions(statusCode, ownerId, progressRate, rootTasksAllCompleted)
        );
    }

    private List<ProjectExecutionLifecycleActionRespVO> buildAvailableActions(String statusCode, Long ownerId,
                                                                              BigDecimal progressRate,
                                                                              boolean rootTasksAllCompleted) {
        List<ObjectStatusTransitionDO> transitions = objectStatusTransitionMapper
                .selectListByObjectTypeAndFromStatus(ProjectExecutionConstants.OBJECT_TYPE, statusCode);
        if (transitions == null || transitions.isEmpty()) {
            return Collections.emptyList();
        }
        Long currentUserId = SecurityFrameworkUtils.getLoginUserId();
        return transitions.stream()
                // 剔除系统级动作 auto_start：由后端业务事件触发，不暴露给前端按钮
                .filter(transition -> !ObjectActivityConstants.PROJECT_ACTION_AUTO_START.equals(transition.getActionCode()))
                // owner-only 字段硬卡：非负责人本人时不返回 complete / cancel / pause / resume 动作
                .filter(transition -> !OWNER_ONLY_ACTIONS.contains(transition.getActionCode())
                        || (currentUserId != null && Objects.equals(ownerId, currentUserId)))
                // 完成动作额外要求：执行进度已达 100，且参与聚合的根任务全部已完成（避免任务仍进行中时执行被闭环）；
                // 暂停、恢复、取消不受进度 / 根任务状态影响。
                .filter(transition -> !ACTION_COMPLETE.equals(transition.getActionCode())
                        || (isCompleteProgressSatisfied(progressRate) && rootTasksAllCompleted))
                .map(transition -> {
                    ProjectExecutionLifecycleActionRespVO action = new ProjectExecutionLifecycleActionRespVO();
                    action.setActionCode(transition.getActionCode());
                    action.setActionName(transition.getActionName());
                    action.setNeedReason(transition.getNeedReason());
                    return action;
                })
                .toList();
    }

    private boolean isCompleteProgressSatisfied(BigDecimal progressRate) {
        return progressRate != null && progressRate.compareTo(COMPLETE_PROGRESS_THRESHOLD) >= 0;
    }

    public record ProjectExecutionLifecycleView(String statusName,
                                                Boolean terminal,
                                                Boolean allowEdit,
                                                List<ProjectExecutionLifecycleActionRespVO> availableActions) {
    }

}
