package com.njcn.rdms.module.project.dal.mysql.project;

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.mapper.BaseMapperX;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.module.project.controller.admin.project.vo.requirement.ProjectRequirementPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectRequirementDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.Collection;
import java.util.List;

/**
 * 项目需求 Mapper
 */
@Mapper
public interface ProjectRequirementMapper extends BaseMapperX<ProjectRequirementDO> {

    /**
     * 分页查询需求列表
     */
    default PageResult<ProjectRequirementDO> selectPage(ProjectRequirementPageReqVO reqVO) {
        return selectPage(reqVO, buildQueryWrapper(reqVO, null));
    }

    /**
     * 分页查询需求列表，并排除指定状态集合。
     */
    default PageResult<ProjectRequirementDO> selectPage(ProjectRequirementPageReqVO reqVO, Collection<String> excludeStatusCodes) {
        return selectPage(reqVO, buildQueryWrapper(reqVO, excludeStatusCodes));
    }

    /**
     * 查询所有符合条件的需求列表，用于树查询
     */
    default List<ProjectRequirementDO> selectList(ProjectRequirementPageReqVO reqVO) {
        return selectList(buildQueryWrapper(reqVO, null));
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapperX<ProjectRequirementDO> buildQueryWrapper(ProjectRequirementPageReqVO reqVO,
                                                                       Collection<String> excludeStatusCodes) {
        LambdaQueryWrapperX<ProjectRequirementDO> queryWrapper = new LambdaQueryWrapperX<>();
        if (StringUtils.hasText(reqVO.getTitle())) {
            queryWrapper.like(ProjectRequirementDO::getTitle, reqVO.getTitle());
        }
        queryWrapper.eqIfPresent(ProjectRequirementDO::getCategory, reqVO.getCategory())
                .eqIfPresent(ProjectRequirementDO::getPriority, reqVO.getPriority())
                .eqIfPresent(ProjectRequirementDO::getStatusCode, reqVO.getStatusCode())
                .eqIfPresent(ProjectRequirementDO::getCurrentHandlerUserId, reqVO.getCurrentHandlerUserId())
                .eqIfPresent(ProjectRequirementDO::getSourceType, reqVO.getSourceType())
                .likeIfPresent(ProjectRequirementDO::getSourceBizCode, reqVO.getSourceBizCode())
                .inIfPresent(ProjectRequirementDO::getModuleId, reqVO.getModuleIds())
                .eqIfPresent(ProjectRequirementDO::getModuleId, reqVO.getModuleId())
                .eqIfPresent(ProjectRequirementDO::getParentId, reqVO.getParentId())
                .eq(ProjectRequirementDO::getProjectId, reqVO.getProjectId());
        if (excludeStatusCodes != null && !excludeStatusCodes.isEmpty()) {
            queryWrapper.notIn(ProjectRequirementDO::getStatusCode, excludeStatusCodes);
        }
        queryWrapper.orderByAsc(ProjectRequirementDO::getSort)
                .orderByDesc(ProjectRequirementDO::getCreateTime);
        return queryWrapper;
    }

    /**
     * 根据父需求 ID 查询子需求列表
     */
    default List<ProjectRequirementDO> selectListByParentId(Long parentId) {
        return selectList(new LambdaQueryWrapperX<ProjectRequirementDO>()
                .eq(ProjectRequirementDO::getParentId, parentId)
                .orderByAsc(ProjectRequirementDO::getSort)
                .orderByDesc(ProjectRequirementDO::getCreateTime));
    }

    /**
     * 根据模块 ID 查询需求列表
     */
    default List<ProjectRequirementDO> selectListByModuleId(Long moduleId) {
        return selectList(new LambdaQueryWrapperX<ProjectRequirementDO>()
                .eq(ProjectRequirementDO::getModuleId, moduleId)
                .orderByAsc(ProjectRequirementDO::getSort));
    }

    /**
     * 带并发控制的状态更新
     */
    default int updateStatusByIdAndStatus(Long id, String fromStatus, String toStatus, String lastStatusReason) {
        ProjectRequirementDO update = new ProjectRequirementDO();
        update.setStatusCode(toStatus);
        update.setLastStatusReason(lastStatusReason);
        return update(update, new LambdaQueryWrapperX<ProjectRequirementDO>()
                .eq(ProjectRequirementDO::getId, id)
                .eq(ProjectRequirementDO::getStatusCode, fromStatus));
    }

    /**
     * 根据 ID 和状态删除，带并发控制
     */
    default int deleteByIdAndStatus(Long id, String statusCode) {
        return delete(new LambdaQueryWrapperX<ProjectRequirementDO>()
                .eq(ProjectRequirementDO::getId, id)
                .eq(ProjectRequirementDO::getStatusCode, statusCode));
    }

    /**
     * 统计指定项目下处于非终态的需求数。用于项目 complete 前置校验（TD-015）。
     * 走索引 idx_rdms_project_requirement_proj_status(project_id, status_code, deleted)（见演示库补丁补齐）。
     */
    default Integer countNonTerminalByProjectId(Long projectId, List<String> terminalStatusCodes) {
        LambdaQueryWrapperX<ProjectRequirementDO> queryWrapper = new LambdaQueryWrapperX<ProjectRequirementDO>()
                .eq(ProjectRequirementDO::getProjectId, projectId);
        if (terminalStatusCodes != null && !terminalStatusCodes.isEmpty()) {
            queryWrapper.notIn(ProjectRequirementDO::getStatusCode, terminalStatusCodes);
        }
        return Math.toIntExact(selectCount(queryWrapper));
    }

    /**
     * 临期/逾期告警候选：预计完成日非空且 <= maxPlannedEndDate，状态不在排除集（终态+paused）。
     * excludeStatusCodes 为空时不排除任何状态（空集守卫，与既有口径一致）。
     * 设计见 docs/domains/project/2026-06-12-临期逾期告警-设计.html。
     */
    default List<ProjectRequirementDO> selectDueAlertCandidateList(LocalDate maxPlannedEndDate,
                                                                   Collection<String> excludeStatusCodes) {
        return selectList(new LambdaQueryWrapperX<ProjectRequirementDO>()
                .isNotNull(ProjectRequirementDO::getExpectedTime)
                .le(ProjectRequirementDO::getExpectedTime, maxPlannedEndDate)
                .notIn(excludeStatusCodes != null && !excludeStatusCodes.isEmpty(),
                        ProjectRequirementDO::getStatusCode, excludeStatusCodes));
    }

}
