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

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.task.vo.worklog.TaskWorklogPageReqVO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.TaskWorklogDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Mapper
public interface TaskWorklogMapper extends BaseMapperX<TaskWorklogDO> {

    /**
     * 按主键 + 任务 ID 双键查；逻辑删除的记录不会命中（依赖 BaseMapper 自带的 deleted=0 过滤）。
     * 用于 update / delete 前的归属校验。
     */
    default TaskWorklogDO selectByIdAndTaskId(Long id, Long taskId) {
        return selectOne(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getId, id)
                .eq(TaskWorklogDO::getTaskId, taskId));
    }

    /**
     * 任务工时分页：按 endDate DESC, id DESC；支持按填报人 / 段相交过滤。
     * 段相交语义：record.startDate <= filter.endDate AND record.endDate >= filter.startDate。
     */
    default PageResult<TaskWorklogDO> selectPageByTaskId(Long taskId, TaskWorklogPageReqVO reqVO) {
        LambdaQueryWrapperX<TaskWorklogDO> queryWrapper = new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getTaskId, taskId)
                .eqIfPresent(TaskWorklogDO::getUserId, reqVO.getUserId())
                .eqIfPresent(TaskWorklogDO::getDifficulty, reqVO.getDifficulty());
        if (reqVO.getEndDate() != null) {
            queryWrapper.le(TaskWorklogDO::getStartDate, reqVO.getEndDate());
        }
        if (reqVO.getStartDate() != null) {
            queryWrapper.ge(TaskWorklogDO::getEndDate, reqVO.getStartDate());
        }
        queryWrapper.orderByDesc(TaskWorklogDO::getEndDate)
                .orderByDesc(TaskWorklogDO::getId);
        return selectPage(reqVO, queryWrapper);
    }

    /**
     * 单任务工时小时数汇总。无记录时返回 0；逻辑删除的记录不参与汇总。
     */
    @Select("""
            SELECT COALESCE(SUM(duration_hours), 0)
            FROM rdms_task_worklog
            WHERE deleted = b'0' AND task_id = #{taskId}
            """)
    BigDecimal sumDurationByTaskId(@Param("taskId") Long taskId);

    /**
     * 项目下所有任务工作日志的最早开始日期。逻辑删除的任务 / 工作日志不参与统计。
     */
    @Select("""
            SELECT MIN(w.start_date)
            FROM rdms_task_worklog w
            INNER JOIN rdms_task t ON t.id = w.task_id
            WHERE w.deleted = b'0'
              AND t.deleted = b'0'
              AND t.project_id = #{projectId}
            """)
    LocalDate selectEarliestStartDateByProjectId(@Param("projectId") Long projectId);

    /**
     * 批量任务工时小时数汇总，返回 [{taskId, total}]。用于详情/分页装配避免 N+1。
     */
    @Select("""
            <script>
            SELECT task_id AS taskId, COALESCE(SUM(duration_hours), 0) AS total
            FROM rdms_task_worklog
            WHERE deleted = b'0' AND task_id IN
              <foreach collection="taskIds" item="id" open="(" separator="," close=")">#{id}</foreach>
            GROUP BY task_id
            </script>
            """)
    List<Map<String, Object>> sumDurationGroupByTaskIds(@Param("taskIds") Collection<Long> taskIds);

    /**
     * 是否存在任意工时记录。叶子转父校验用（拆子任务前必须删完工时）。
     */
    default boolean existsByTaskId(Long taskId) {
        if (taskId == null) {
            return false;
        }
        return selectCount(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getTaskId, taskId)) > 0;
    }

    /**
     * 任务下最早一条工作日志（按 start_date asc, create_time asc, id asc）。
     */
    default TaskWorklogDO selectEarliestByTaskId(Long taskId) {
        if (taskId == null) {
            return null;
        }
        List<TaskWorklogDO> list = selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getTaskId, taskId)
                .orderByAsc(TaskWorklogDO::getStartDate)
                .orderByAsc(BaseDO::getCreateTime)
                .orderByAsc(TaskWorklogDO::getId)
                .last("LIMIT 1"));
        return list.isEmpty() ? null : list.get(0);
    }

    /**
     * 取指定用户在该任务下最新的一条工时（按 end_date desc, create_time desc, id desc）。
     * 用于 owner 填报后回查"本人最新一条"以同步任务进度。
     * 逻辑删除的记录由 BaseMapper 自动过滤；无记录返回 null。
     */
    default TaskWorklogDO selectLatestByTaskIdAndUserId(Long taskId, Long userId) {
        if (taskId == null || userId == null) {
            return null;
        }
        List<TaskWorklogDO> list = selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getTaskId, taskId)
                .eq(TaskWorklogDO::getUserId, userId)
                .orderByDesc(TaskWorklogDO::getEndDate)
                .orderByDesc(TaskWorklogDO::getCreateTime)
                .orderByDesc(TaskWorklogDO::getId)
                .last("LIMIT 1"));
        return list.isEmpty() ? null : list.get(0);
    }

    /**
     * 取该任务下指定用户 progressRate=100 的最晚一条工作日志（按 end_date desc, create_time desc, id desc）。
     */
    default TaskWorklogDO selectLatestCompletedByTaskIdAndUserId(Long taskId, Long userId) {
        if (taskId == null || userId == null) {
            return null;
        }
        List<TaskWorklogDO> list = selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getTaskId, taskId)
                .eq(TaskWorklogDO::getUserId, userId)
                .eq(TaskWorklogDO::getProgressRate, new BigDecimal("100"))
                .orderByDesc(TaskWorklogDO::getEndDate)
                .orderByDesc(BaseDO::getCreateTime)
                .orderByDesc(TaskWorklogDO::getId)
                .last("LIMIT 1"));
        return list.isEmpty() ? null : list.get(0);
    }

    /**
     * 取该 (taskId, userId) 下 endDate 严格早于给定值的"最近一条"，按 end_date desc, id desc 取首行。
     * 用于进度单调性校验（与"前一段"比较）。excludeId 不为 null 时排除自身（更新场景）。
     */
    default TaskWorklogDO selectPrevByEndDate(Long taskId, Long userId, LocalDate endDate, Long excludeId) {
        if (taskId == null || userId == null || endDate == null) {
            return null;
        }
        LambdaQueryWrapperX<TaskWorklogDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(TaskWorklogDO::getTaskId, taskId)
                .eq(TaskWorklogDO::getUserId, userId)
                .lt(TaskWorklogDO::getEndDate, endDate);
        if (excludeId != null) {
            queryWrapper.ne(TaskWorklogDO::getId, excludeId);
        }
        queryWrapper.orderByDesc(TaskWorklogDO::getEndDate)
                .orderByDesc(TaskWorklogDO::getId)
                .last("LIMIT 1");
        List<TaskWorklogDO> list = selectList(queryWrapper);
        return list.isEmpty() ? null : list.get(0);
    }

    /**
     * 取该 (taskId, userId) 下 endDate 严格晚于给定值的"最近一条"，按 end_date asc, id asc 取首行。
     * 用于进度单调性校验（与"后一段"比较）。excludeId 不为 null 时排除自身（更新场景）。
     */
    default TaskWorklogDO selectNextByEndDate(Long taskId, Long userId, LocalDate endDate, Long excludeId) {
        if (taskId == null || userId == null || endDate == null) {
            return null;
        }
        LambdaQueryWrapperX<TaskWorklogDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(TaskWorklogDO::getTaskId, taskId)
                .eq(TaskWorklogDO::getUserId, userId)
                .gt(TaskWorklogDO::getEndDate, endDate);
        if (excludeId != null) {
            queryWrapper.ne(TaskWorklogDO::getId, excludeId);
        }
        queryWrapper.orderByAsc(TaskWorklogDO::getEndDate)
                .orderByAsc(TaskWorklogDO::getId)
                .last("LIMIT 1");
        List<TaskWorklogDO> list = selectList(queryWrapper);
        return list.isEmpty() ? null : list.get(0);
    }

    /**
     * 是否存在与指定 [startDate, endDate] 区间相交的、属于该 task × user 的工时记录。
     * 段相交语义：record.startDate <= endDate AND record.endDate >= startDate。
     * 用于禁止重叠校验；excludeId 不为 null 时排除该记录自身（更新场景用）。
     */
    default boolean existsOverlapping(Long taskId, Long userId, LocalDate startDate, LocalDate endDate, Long excludeId) {
        if (taskId == null || userId == null || startDate == null || endDate == null) {
            return false;
        }
        LambdaQueryWrapperX<TaskWorklogDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(TaskWorklogDO::getTaskId, taskId)
                .eq(TaskWorklogDO::getUserId, userId)
                .le(TaskWorklogDO::getStartDate, endDate)
                .ge(TaskWorklogDO::getEndDate, startDate);
        if (excludeId != null) {
            queryWrapper.ne(TaskWorklogDO::getId, excludeId);
        }
        return selectCount(queryWrapper) > 0;
    }

    /**
     * 按 task_id 集合批量软删工作日志。用于级联删除任务时一并清理。
     */
    default int deleteByTaskIdIn(Collection<Long> taskIds) {
        if (taskIds == null || taskIds.isEmpty()) {
            return 0;
        }
        return delete(new LambdaQueryWrapperX<TaskWorklogDO>()
                .in(TaskWorklogDO::getTaskId, taskIds));
    }

    /**
     * 单任务工作日志条数（用于删除预检）。
     */
    default int countByTaskId(Long taskId) {
        if (taskId == null) {
            return 0;
        }
        return Math.toIntExact(selectCount(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getTaskId, taskId)));
    }

    default List<TaskWorklogDO> selectListByUserIdAndPeriod(Long userId, LocalDate startDate, LocalDate endDate) {
        if (userId == null || startDate == null || endDate == null) {
            return List.of();
        }
        return selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
                .eq(TaskWorklogDO::getUserId, userId)
                .le(TaskWorklogDO::getStartDate, endDate)
                .ge(TaskWorklogDO::getEndDate, startDate)
                .orderByAsc(TaskWorklogDO::getTaskId)
                .orderByAsc(TaskWorklogDO::getEndDate)
                .orderByAsc(TaskWorklogDO::getId));
    }

    default List<TaskWorklogDO> selectListByTaskIdsAndPeriod(Collection<Long> taskIds, LocalDate startDate, LocalDate endDate) {
        if (taskIds == null || taskIds.isEmpty() || startDate == null || endDate == null) {
            return List.of();
        }
        return selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
                .in(TaskWorklogDO::getTaskId, taskIds)
                .le(TaskWorklogDO::getStartDate, endDate)
                .ge(TaskWorklogDO::getEndDate, startDate)
                .orderByAsc(TaskWorklogDO::getTaskId)
                .orderByAsc(TaskWorklogDO::getEndDate)
                .orderByAsc(TaskWorklogDO::getId));
    }

    /** selectListByUserIdAndPeriod 的多用户版,团队工时周聚合用。段相交语义相同。 */
    default List<TaskWorklogDO> selectListByUserIdsAndPeriod(Collection<Long> userIds,
                                                             LocalDate startDate, LocalDate endDate) {
        if (userIds == null || userIds.isEmpty() || startDate == null || endDate == null) {
            return List.of();
        }
        return selectList(new LambdaQueryWrapperX<TaskWorklogDO>()
                .in(TaskWorklogDO::getUserId, userIds)
                .le(TaskWorklogDO::getStartDate, endDate)
                .ge(TaskWorklogDO::getEndDate, startDate)
                .orderByAsc(TaskWorklogDO::getUserId)
                .orderByAsc(TaskWorklogDO::getEndDate)
                .orderByAsc(TaskWorklogDO::getId));
    }

}
