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

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.worklog.TaskWorklogPageReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.worklog.TaskWorklogRespVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.worklog.TaskWorklogSaveReqVO;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 任务工时 Service。
 * <p>
 * 决策来源：docs/项目/2026-05-09-task-worklog-design.md。
 * 核心约束：仅叶子任务可挂工时；填报人限制为 owner + 在岗协办人；
 * 按段记录（startDate/endDate 必填，单天=二者相等）；同人同任务下日期范围禁止重叠；
 * 颗粒：durationHours 必须 > 0 且为 0.5 的整数倍；
 * 进度：owner 填报触发任务进度同步（按 endDate 排序取本人最新一条），协作人填报仅本人自评。
 */
public interface TaskWorklogService {

    /**
     * 任务工时分页（按 endDate DESC, id DESC）。
     * 支持按填报人 / 段相交过滤；上下文校验仅要求项目/执行/任务存在，不要求允许编辑。
     */
    PageResult<TaskWorklogRespVO> getWorklogPage(Long projectId, Long executionId, Long taskId,
                                                 TaskWorklogPageReqVO reqVO);

    /**
     * 新增工时记录。校验：上下文可编辑、任务为叶子、登录人是 owner 或在岗协办人、
     * 段日期合法、与已有记录不重叠、时长合法。
     * 填报人 userId 取登录用户，前端不传。返回新建记录编号。
     */
    Long createWorklog(Long projectId, Long executionId, Long taskId, TaskWorklogSaveReqVO reqVO);

    /**
     * 修改工时记录（含起止日期/时长/进度/工作内容/附件）。校验：记录归属任务、登录人是该记录原填报人、
     * 段日期合法、与该用户其他记录不重叠（排除自身）、时长合法。
     * 不允许修改 taskId / userId（前端不可传）。
     */
    void updateWorklog(Long projectId, Long executionId, Long taskId, Long worklogId,
                       TaskWorklogSaveReqVO reqVO);

    /**
     * 删除工时记录。校验：记录归属任务、登录人是原填报人或当前任务负责人。逻辑删除。
     */
    void deleteWorklog(Long projectId, Long executionId, Long taskId, Long worklogId);

    /**
     * 批量任务工时小时数汇总，用于详情/分页装配 totalSpentHours，避免 N+1。
     * 任务无任何工时时不会出现在结果中（调用方需用默认 0 兜底）。
     */
    Map<Long, BigDecimal> sumDurationGroupedByTaskIds(Collection<Long> taskIds);

    /**
     * 单任务工时小时数汇总。无记录返回 0。
     */
    default BigDecimal sumDurationByTaskId(Long taskId) {
        if (taskId == null) {
            return BigDecimal.ZERO;
        }
        return sumDurationGroupedByTaskIds(Collections.singletonList(taskId))
                .getOrDefault(taskId, BigDecimal.ZERO);
    }

}
