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

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.dataobject.BaseDO;
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.execution.vo.execution.ProjectExecutionStatusBoardReqVO;
import com.njcn.rdms.module.project.controller.admin.project.execution.vo.execution.ProjectExecutionPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.project.execution.ProjectExecutionDO;
import com.njcn.rdms.module.project.service.project.permission.VisibilityScope;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.util.StringUtils;

import java.util.List;

@Mapper
public interface ProjectExecutionMapper extends BaseMapperX<ProjectExecutionDO> {

    default ProjectExecutionDO selectByProjectIdAndId(Long projectId, Long executionId) {
        return selectOne(new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getProjectId, projectId)
                .eq(ProjectExecutionDO::getId, executionId));
    }

    default ProjectExecutionDO selectByProjectIdAndName(Long projectId, String executionName) {
        return selectOne(new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getProjectId, projectId)
                .eq(ProjectExecutionDO::getExecutionName, executionName));
    }

    default PageResult<ProjectExecutionDO> selectPageByProjectId(Long projectId,
                                                                 VisibilityScope scope,
                                                                 ProjectExecutionPageReqVO reqVO) {
        // 可见性短路：非 seesAll 且无任何可见执行 → 空页，避免后续 IN () SQL
        if (!scope.seesAll() && scope.executionIds().isEmpty()) {
            return PageResult.empty();
        }
        LambdaQueryWrapperX<ProjectExecutionDO> queryWrapper = new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getProjectId, projectId)
                .eqIfPresent(ProjectExecutionDO::getExecutionType, reqVO.getExecutionType())
                .eqIfPresent(ProjectExecutionDO::getOwnerId, reqVO.getOwnerId())
                .eqIfPresent(ProjectExecutionDO::getStatusCode, reqVO.getStatusCode())
                .betweenIfPresent(BaseDO::getUpdateTime, reqVO.getUpdateTime())
                .orderByDesc(BaseDO::getCreateTime)
                .orderByDesc(ProjectExecutionDO::getId);
        if (StringUtils.hasText(reqVO.getKeyword())) {
            queryWrapper.and(wrapper -> wrapper.like(ProjectExecutionDO::getExecutionName, reqVO.getKeyword()));
        }
        if (!scope.seesAll()) {
            queryWrapper.in(ProjectExecutionDO::getId, scope.executionIds());
        }
        return selectPage(reqVO, queryWrapper);
    }

    /**
     * 查 userId 在指定项目下，作为 owner 的所有执行 ID。
     * 用于 VisibilityScopeResolver 收集"我是执行负责人"的 scope 来源。
     */
    default List<Long> selectIdsByProjectIdAndOwnerId(Long projectId, Long userId) {
        return selectList(new LambdaQueryWrapperX<ProjectExecutionDO>()
                        .select(ProjectExecutionDO::getId)
                        .eq(ProjectExecutionDO::getProjectId, projectId)
                        .eq(ProjectExecutionDO::getOwnerId, userId))
                .stream()
                .map(ProjectExecutionDO::getId)
                .toList();
    }

    default Integer countNonTerminalByProjectIdAndOwnerId(Long projectId, Long ownerId, List<String> terminalStatusCodes) {
        LambdaQueryWrapperX<ProjectExecutionDO> queryWrapper = new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getProjectId, projectId)
                .eq(ProjectExecutionDO::getOwnerId, ownerId);
        if (terminalStatusCodes != null && !terminalStatusCodes.isEmpty()) {
            queryWrapper.notIn(ProjectExecutionDO::getStatusCode, terminalStatusCodes);
        }
        return Math.toIntExact(selectCount(queryWrapper));
    }

    default Integer countByProjectIdAndStatusCode(Long projectId,
                                                  VisibilityScope scope,
                                                  ProjectExecutionStatusBoardReqVO reqVO,
                                                  String statusCode) {
        // 可见性短路：非 seesAll 且无任何可见执行 → 计数 0
        if (!scope.seesAll() && scope.executionIds().isEmpty()) {
            return 0;
        }
        LambdaQueryWrapperX<ProjectExecutionDO> queryWrapper = new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getProjectId, projectId)
                .eq(ProjectExecutionDO::getStatusCode, statusCode)
                .eqIfPresent(ProjectExecutionDO::getExecutionType, reqVO.getExecutionType())
                .eqIfPresent(ProjectExecutionDO::getOwnerId, reqVO.getOwnerId())
                .betweenIfPresent(BaseDO::getUpdateTime, reqVO.getUpdateTime());
        if (StringUtils.hasText(reqVO.getKeyword())) {
            queryWrapper.and(wrapper -> wrapper.like(ProjectExecutionDO::getExecutionName, reqVO.getKeyword()));
        }
        if (!scope.seesAll()) {
            queryWrapper.in(ProjectExecutionDO::getId, scope.executionIds());
        }
        return Math.toIntExact(selectCount(queryWrapper));
    }

    default int updateStatusByIdAndStatus(Long id, String fromStatus, String toStatus, String lastStatusReason) {
        ProjectExecutionDO update = new ProjectExecutionDO();
        update.setStatusCode(toStatus);
        update.setLastStatusReason(lastStatusReason);
        return update(update, new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getId, id)
                .eq(ProjectExecutionDO::getStatusCode, fromStatus));
    }

    /**
     * 软删执行（按状态 CAS）。仅在 statusCode 与传入 fromStatus 匹配时才标 deleted=1。
     * 返回 1 表示成功；返回 0 视为并发修改。
     */
    default int deleteByIdAndStatus(Long id, String fromStatus) {
        return delete(new LambdaQueryWrapperX<ProjectExecutionDO>()
                .eq(ProjectExecutionDO::getId, id)
                .eq(ProjectExecutionDO::getStatusCode, fromStatus));
    }

}
