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

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskDeletePrecheckRespVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskDeleteReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskPageReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskRespVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskSaveReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskStatusActionReqVO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.ProjectTaskDO;

/**
 * 项目任务 Service 接口。
 */
public interface ProjectTaskService {

    Long createTask(Long projectId, Long executionId, ProjectTaskSaveReqVO reqVO);

    void updateTask(Long projectId, Long executionId, ProjectTaskSaveReqVO reqVO);

    ProjectTaskDO getTask(Long projectId, Long executionId, Long taskId);

    PageResult<ProjectTaskDO> getTaskPage(Long projectId, Long executionId, ProjectTaskPageReqVO reqVO);

    /**
     * 获取任务详情 VO，附带状态生命周期与负责人昵称。
     */
    ProjectTaskRespVO getTaskRespVO(Long projectId, Long executionId, Long taskId);

    /**
     * 获取任务分页 VO，附带状态生命周期与负责人昵称（昵称按 ownerId 去重批量查询，避免 N+1）。
     */
    PageResult<ProjectTaskRespVO> getTaskRespVOPage(Long projectId, Long executionId, ProjectTaskPageReqVO reqVO);

    /**
     * 把任务 DO 分页结果整体装配成 RespVO 分页结果。
     * <p>提供给"看板分页接口"复用同款装配口径，保证两个接口列元素结构 / 序列化完全一致；
     * 看板分页内部按状态列循环时，应调用本方法装配每列，不要自行重复装配。
     */
    PageResult<ProjectTaskRespVO> assembleTaskRespVOPage(Long projectId, Long executionId,
                                                        PageResult<ProjectTaskDO> doPage);

    /**
     * 跨执行装配 ProjectTaskRespVO 分页结果。
     *
     * 与 {@link #assembleTaskRespVOPage(Long, Long, PageResult)} 区别:
     * 本方法不绑单个 executionId,允许 page 内任务来自项目下任意多个执行;
     * 装配时按 task.executionId 分组批量回填 executionName / executionStatusCode
     * (走 enrichExecutionInfo helper)。
     * <p><b>不填充字段</b>:executionOwnerId / projectRequirementName / projectRequirementStatusCode
     * (跨多 execution 场景无法共享单 execution 上下文)。前端跨执行视图按需处理。</p>
     */
    PageResult<ProjectTaskRespVO> assembleTaskRespVOPageCrossExecution(Long projectId, PageResult<ProjectTaskDO> doPage);

    void changeTaskStatus(Long projectId, Long executionId, Long taskId, ProjectTaskStatusActionReqVO reqVO);

    /**
     * 删除任务（软删 + 三重确认 + 多身份授权 + 级联软删 + 父进度回算 + 审计）。
     * <p>删除规则：非 completed 即可删（pending / active / paused / cancelled 全允许）；
     * 已 completed 的任务用专门错误码 PROJECT_TASK_NOT_ALLOW_DELETE 拦截。
     * <p>授权：项目负责人 / 执行负责人 / 任务负责人 / 父任务负责人均可删；
     * 其它用户持有 {@code project:task:delete} 时作为管理员兜底放行。
     * <p>三重确认：{@code taskName} / {@code confirmText}（DELETE 或 删除）/ {@code reason} 全部必填，
     * 任意一项缺失或不匹配即拒。
     * <p>级联范围：软删该任务及其所有子孙任务、所有相关工作日志、所有相关任务协办；
     * 执行 / 项目需求 progressRate 是读时聚合，无需主动刷新。
     * <p>父进度回算：删完后若有 parent_task_id，触发 {@code recalcParentProgressFrom} 把祖先链路进度重算。
     * <p>审计：写一条 {@code TASK_ACTION_DELETE} 审计记录，reason 入审计上下文。
     */
    void deleteTask(Long projectId, Long executionId, Long taskId, ProjectTaskDeleteReqVO reqVO);

    /**
     * 任务删除前的下挂数据预检：返回子任务数 + 工作日志数 + hasDependentData 标记。
     * <p>前端依据该结果分流：无下挂走简化确认路径，有下挂走重型确认路径。
     * <p>本接口为只读预检，不变更任何数据；删除规则与级联范围的最终校验仍由 deleteTask 负责。
     */
    ProjectTaskDeletePrecheckRespVO precheckDeleteTask(Long projectId, Long executionId, Long taskId);

    /**
     * 以"任务负责人本人最新一条工时"的进度为准，同步到任务自身 progressRate 并触发父任务 AVG 重算。
     * 由工时模块在 owner 维度的 worklog create/update/delete 后调用。
     * 若 owner 当前在该任务下不存在任何工时记录，则保留 task.progress_rate 原值不动（避免删除场景下意外归零）。
     * 仅对叶子任务生效；父任务由子任务汇总驱动，不走该路径。
     */
    void syncOwnerProgressFromLatestWorklog(Long taskId);

    /**
     * 由工时填报（5.11）触发的任务自动开始：当任务当前处于初始态（initialFlag=true）时，
     * 走一次 {@link com.njcn.rdms.module.project.constant.ObjectActivityConstants#TASK_ACTION_AUTO_START}
     * 动作把任务推进到下一状态，并写状态日志 / 审计日志。
     * <p>
     * 调用方必须已自行确认登录人是 task.ownerId（仅 owner 工时驱动状态推进，与 progressRate 同步口径一致）。
     * 本方法**不走** @CheckObjectPermission，因为 5.11 持有的是 PERMISSION_WORKLOG，
     * 而 5.5 changeTaskStatus 持有的是 PERMISSION_STATUS，两者权限边界不同。
     * <p>
     * 容错：若任务当前状态非初始态、transition 配置缺失/禁用、并发被抢占（affected=0）等情况，
     * 本方法静默 return（仅打 WARN 日志），不影响工时主流程入库。
     */
    void internalAutoStartByWorklog(ProjectTaskDO task);

    /**
     * 按工作日志事实回算任务实际开始/结束日期：
     * <ul>
     *   <li>actualStartDate = 该任务最早一条工作日志的 startDate（不区分填报人）</li>
     *   <li>actualEndDate = 该任务负责人本人所填、progressRate=100 的最晚一条工作日志 endDate</li>
     * </ul>
     * <p>
     * 当日志被删除或改动后，本方法也负责把对应字段清空或改写为新的回算结果。
     */
    void syncActualDatesFromWorklogs(Long taskId);

    /**
     * 由执行 cancel 触发的级联：取消指定执行下所有未终态的顶层任务（parentTaskId IS NULL）。
     * 顶层任务自身的内部链路会再级联自己的子任务，整棵子树通过链式实现。
     * 跳过任务侧的 owner 校验（系统行为），但复用 doInternalChangeTaskStatus 的事务 / CAS / 审计 / 实际日期回填等。
     * 调用方：ProjectExecutionServiceImpl 在 cancel 成功后追加。
     */
    void cascadeCancelTasksByExecutionId(Long executionId, String executionReason);

    /**
     * 由执行 pause 触发的级联：暂停指定执行下所有顶层任务中状态为 active 的节点。
     * 顶层任务自身会再级联子任务，整棵子树同步暂停。
     */
    void cascadePauseTasksByExecutionId(Long executionId, String executionReason);

    /**
     * 由执行 resume 触发的级联：恢复指定执行下所有顶层任务中状态为 paused 的节点。
     * 顶层任务自身会再级联子任务，整棵子树同步恢复。
     * "误恢复"边界（任务级 paused 与父级 paused 不区分）与任务侧 §4.4 同款，已识别并接受。
     */
    void cascadeResumeTasksByExecutionId(Long executionId, String executionReason);

}
