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

import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.project.constant.ObjectActivityConstants;
import com.njcn.rdms.module.project.constant.ProjectTaskConstants;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskLifecycleActionRespVO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.ProjectTaskDO;
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.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

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 task.ownerId == currentUserId} 字段硬卡过滤，
 *       与 {@link ProjectTaskServiceImpl#validateOwnerForAction} 同款判定。</li>
 *   <li>对 {@code complete} 动作叠加进度过滤，任务进度未达到 100 时不下发完成按钮。</li>
 * </ol>
 * 非状态动作（delete / 加协办人 / 工时填报等）的权限码 / 字段过滤未纳入本字段，前端按各动作对应权限码与 owner 字段独立判断；
 * 全量化纳入 {@code availableActions} 留待后续阶段统一改造。
 */
@Service
public class ProjectTaskStatusViewService {

    /**
     * 状态推进动作中要求 owner-only 字段硬卡的集合，与 ProjectTaskServiceImpl#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 ProjectTaskLifecycleView getLifecycle(String statusCode, Long ownerId, BigDecimal progressRate) {
        ObjectStatusModelDO statusModel = objectStatusModelMapper
                .selectByObjectTypeAndStatusCodeEnabled(ProjectTaskConstants.OBJECT_TYPE, statusCode);
        if (statusModel == null) {
            throw exception(ErrorCodeConstants.PROJECT_TASK_STATUS_MODEL_NOT_EXISTS_OR_DISABLED);
        }
        return new ProjectTaskLifecycleView(
                statusModel.getStatusName(),
                statusModel.getTerminalFlag(),
                statusModel.getAllowEdit(),
                buildAvailableActions(statusCode, ownerId, progressRate)
        );
    }

    public Map<Long, ProjectTaskLifecycleView> getLifecycleMap(List<ProjectTaskDO> tasks) {
        if (tasks == null || tasks.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<String, ObjectStatusModelDO> statusModelMap = objectStatusModelMapper
                .selectListByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE).stream()
                .collect(Collectors.toMap(ObjectStatusModelDO::getStatusCode, Function.identity(), (a, b) -> a));
        List<String> statusCodes = tasks.stream()
                .map(ProjectTaskDO::getStatusCode)
                .filter(Objects::nonNull)
                .distinct()
                .toList();
        Map<String, List<ObjectStatusTransitionDO>> transitionMap = statusCodes.isEmpty()
                ? Collections.emptyMap()
                : objectStatusTransitionMapper
                .selectListByObjectTypeAndFromStatuses(ProjectTaskConstants.OBJECT_TYPE, statusCodes).stream()
                .collect(Collectors.groupingBy(ObjectStatusTransitionDO::getFromStatusCode));
        Long currentUserId = SecurityFrameworkUtils.getLoginUserId();
        Map<Long, ProjectTaskLifecycleView> result = new LinkedHashMap<>();
        for (ProjectTaskDO task : tasks) {
            ObjectStatusModelDO statusModel = statusModelMap.get(task.getStatusCode());
            if (statusModel == null) {
                throw exception(ErrorCodeConstants.PROJECT_TASK_STATUS_MODEL_NOT_EXISTS_OR_DISABLED);
            }
            result.put(task.getId(), new ProjectTaskLifecycleView(
                    statusModel.getStatusName(),
                    statusModel.getTerminalFlag(),
                    statusModel.getAllowEdit(),
                    buildAvailableActions(
                            transitionMap.getOrDefault(task.getStatusCode(), Collections.emptyList()),
                            task.getOwnerId(), task.getProgressRate(), currentUserId)
            ));
        }
        return result;
    }

    private List<ProjectTaskLifecycleActionRespVO> buildAvailableActions(String statusCode, Long ownerId,
                                                                         BigDecimal progressRate) {
        List<ObjectStatusTransitionDO> transitions = objectStatusTransitionMapper
                .selectListByObjectTypeAndFromStatus(ProjectTaskConstants.OBJECT_TYPE, statusCode);
        return buildAvailableActions(transitions, ownerId, progressRate, SecurityFrameworkUtils.getLoginUserId());
    }

    private List<ProjectTaskLifecycleActionRespVO> buildAvailableActions(List<ObjectStatusTransitionDO> transitions,
                                                                         Long ownerId,
                                                                         BigDecimal progressRate,
                                                                         Long currentUserId) {
        if (transitions == null || transitions.isEmpty()) {
            return Collections.emptyList();
        }
        return transitions.stream()
                // 剔除系统级动作 auto_start：由工时填报触发，不暴露给前端按钮
                .filter(transition -> !ObjectActivityConstants.TASK_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))
                .map(transition -> {
                    ProjectTaskLifecycleActionRespVO action = new ProjectTaskLifecycleActionRespVO();
                    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 ProjectTaskLifecycleView(String statusName,
                                           Boolean terminal,
                                           Boolean allowEdit,
                                           List<ProjectTaskLifecycleActionRespVO> availableActions) {
    }

}
