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

import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.module.project.constant.ProjectExecutionConstants;
import com.njcn.rdms.module.project.constant.ProjectObjectConstants;
import com.njcn.rdms.module.project.constant.ProjectTaskConstants;
import com.njcn.rdms.module.project.framework.security.annotation.CheckObjectPermission;
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.ProjectExecutionStatusBoardRespVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskBoardPageReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskBoardPageRespVO;
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.ProjectTaskStatusBoardReqVO;
import com.njcn.rdms.module.project.controller.admin.project.task.vo.ProjectTaskStatusBoardRespVO;
import com.njcn.rdms.module.project.dal.dataobject.project.task.ProjectTaskDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.mysql.project.execution.ProjectExecutionMapper;
import com.njcn.rdms.module.project.dal.mysql.project.task.ProjectTaskMapper;
import com.njcn.rdms.module.project.dal.mysql.status.ObjectStatusModelMapper;
import com.njcn.rdms.module.project.service.project.task.ProjectTaskService;
import com.njcn.rdms.module.project.util.DueRangeSupport;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class ProjectStatusBoardServiceImpl implements ProjectStatusBoardService {

    @Resource
    private ObjectStatusModelMapper objectStatusModelMapper;
    @Resource
    private ProjectExecutionMapper projectExecutionMapper;
    @Resource
    private ProjectTaskMapper projectTaskMapper;
    @Resource
    private ProjectTaskService projectTaskService;

    @Override
    @CheckObjectPermission(objectType = ProjectObjectConstants.OBJECT_TYPE, objectId = "#projectId", accessible = true)
    public ProjectExecutionStatusBoardRespVO getExecutionStatusBoard(Long projectId, ProjectExecutionStatusBoardReqVO reqVO) {
        List<ObjectStatusModelDO> statusModels = objectStatusModelMapper.selectListByObjectTypeEnabled(ProjectExecutionConstants.OBJECT_TYPE);
        return buildExecutionStatusBoard(projectId, reqVO, statusModels);
    }

    @Override
    @CheckObjectPermission(objectType = ProjectObjectConstants.OBJECT_TYPE, objectId = "#projectId", accessible = true)
    public ProjectTaskStatusBoardRespVO getTaskStatusBoard(Long projectId, Long executionId, ProjectTaskStatusBoardReqVO reqVO) {
        List<ObjectStatusModelDO> statusModels = objectStatusModelMapper.selectListByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE);
        return buildTaskStatusBoard(projectId, executionId, reqVO, statusModels);
    }

    @Override
    @CheckObjectPermission(objectType = ProjectObjectConstants.OBJECT_TYPE, objectId = "#projectId", accessible = true)
    public ProjectTaskBoardPageRespVO getTaskBoardPage(Long projectId, Long executionId, ProjectTaskBoardPageReqVO reqVO) {
        List<ObjectStatusModelDO> statusModels = objectStatusModelMapper
                .selectListByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE);

        // 列选择：入参为空 → 全集；非空 → 与字典做交集（字典外 statusCode 静默忽略）
        Set<String> selected = collectSelectedStatusCodes(reqVO.getStatusCode());
        List<ObjectStatusModelDO> targetStatusModels = selected.isEmpty()
                ? statusModels
                : statusModels.stream()
                        .filter(model -> selected.contains(model.getStatusCode()))
                        .collect(Collectors.toList());

        ProjectTaskBoardPageRespVO respVO = new ProjectTaskBoardPageRespVO();
        List<ProjectTaskBoardPageRespVO.ColumnItemVO> items = targetStatusModels.stream()
                .map(statusModel -> buildBoardColumn(projectId, executionId, reqVO, statusModel))
                .collect(Collectors.toList());
        respVO.setItems(items);
        return respVO;
    }

    /**
     * 把入参 statusCode 数组归一化成一个去重 Set；null / 空 / 全 blank 都视为"不选列 = 全集"。
     */
    private Set<String> collectSelectedStatusCodes(String[] statusCodes) {
        if (statusCodes == null || statusCodes.length == 0) {
            return Collections.emptySet();
        }
        return Arrays.stream(statusCodes)
                .filter(Objects::nonNull)
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }

    private ProjectTaskBoardPageRespVO.ColumnItemVO buildBoardColumn(Long projectId, Long executionId,
                                                                     ProjectTaskBoardPageReqVO reqVO,
                                                                     ObjectStatusModelDO statusModel) {
        ProjectTaskPageReqVO innerReq = toInnerPageReq(reqVO, statusModel.getStatusCode());
        PageResult<ProjectTaskDO> doPage = projectTaskMapper.selectPageByExecutionId(projectId, executionId, innerReq);
        PageResult<ProjectTaskRespVO> voPage = projectTaskService.assembleTaskRespVOPage(projectId, executionId, doPage);

        ProjectTaskBoardPageRespVO.ColumnItemVO item = new ProjectTaskBoardPageRespVO.ColumnItemVO();
        item.setStatusCode(statusModel.getStatusCode());
        item.setStatusName(statusModel.getStatusName());
        item.setSort(statusModel.getSort());
        item.setTerminal(statusModel.getTerminalFlag());
        item.setList(voPage.getList() == null ? Collections.emptyList() : voPage.getList());
        item.setTotal(voPage.getTotal() == null ? 0L : voPage.getTotal());
        return item;
    }

    /**
     * 把看板分页入参翻译成单状态列的 /tasks/page 入参，复用现有 mapper 与装配逻辑。
     */
    private ProjectTaskPageReqVO toInnerPageReq(ProjectTaskBoardPageReqVO reqVO, String statusCode) {
        ProjectTaskPageReqVO innerReq = new ProjectTaskPageReqVO();
        innerReq.setPageNo(reqVO.getPageNo());
        innerReq.setPageSize(reqVO.getPageSize());
        innerReq.setKeyword(reqVO.getKeyword());
        innerReq.setParentTaskId(reqVO.getParentTaskId());
        innerReq.setInvolveUserId(reqVO.getInvolveUserId());
        innerReq.setOwnerId(reqVO.getOwnerId());
        innerReq.setPriority(reqVO.getPriority());
        innerReq.setUpdateTime(reqVO.getUpdateTime());
        innerReq.setStatusCode(statusCode);
        return innerReq;
    }

    private ProjectExecutionStatusBoardRespVO buildExecutionStatusBoard(Long projectId,
                                                                        ProjectExecutionStatusBoardReqVO reqVO,
                                                                        List<ObjectStatusModelDO> statusModels) {
        // dueRange 截止时间过滤所需的日期边界与执行终态码（终态排除口径对齐任务 summary）。
        LocalDate today = DueRangeSupport.today();
        LocalDate weekStart = DueRangeSupport.weekStart(today);
        LocalDate weekEnd = DueRangeSupport.weekEnd(today);
        List<String> terminalStatusCodes = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectExecutionConstants.OBJECT_TYPE);

        ProjectExecutionStatusBoardRespVO respVO = new ProjectExecutionStatusBoardRespVO();
        List<ProjectExecutionStatusBoardRespVO.ProjectStatusBoardItemVO> items = statusModels.stream().map(statusModel -> {
            ProjectExecutionStatusBoardRespVO.ProjectStatusBoardItemVO item =
                    new ProjectExecutionStatusBoardRespVO.ProjectStatusBoardItemVO();
            item.setStatusCode(statusModel.getStatusCode());
            item.setStatusName(statusModel.getStatusName());
            item.setCount(projectExecutionMapper.countByProjectIdAndStatusCode(projectId, reqVO,
                    statusModel.getStatusCode(), terminalStatusCodes, today, weekStart, weekEnd).longValue());
            item.setSort(statusModel.getSort());
            item.setTerminal(statusModel.getTerminalFlag());
            return item;
        }).toList();
        respVO.setItems(items);
        respVO.setTotal(items.stream().mapToLong(ProjectExecutionStatusBoardRespVO.ProjectStatusBoardItemVO::getCount).sum());
        return respVO;
    }

    private ProjectTaskStatusBoardRespVO buildTaskStatusBoard(Long projectId, Long executionId,
                                                              ProjectTaskStatusBoardReqVO reqVO,
                                                              List<ObjectStatusModelDO> statusModels) {
        ProjectTaskStatusBoardRespVO respVO = new ProjectTaskStatusBoardRespVO();
        List<ProjectTaskStatusBoardRespVO.ProjectStatusBoardItemVO> items = statusModels.stream().map(statusModel -> {
            ProjectTaskStatusBoardRespVO.ProjectStatusBoardItemVO item = new ProjectTaskStatusBoardRespVO.ProjectStatusBoardItemVO();
            item.setStatusCode(statusModel.getStatusCode());
            item.setStatusName(statusModel.getStatusName());
            item.setCount(projectTaskMapper.countByProjectIdAndExecutionIdAndStatusCode(projectId, executionId, reqVO,
                    statusModel.getStatusCode()).longValue());
            item.setSort(statusModel.getSort());
            item.setTerminal(statusModel.getTerminalFlag());
            return item;
        }).toList();
        respVO.setItems(items);
        respVO.setTotal(items.stream().mapToLong(ProjectTaskStatusBoardRespVO.ProjectStatusBoardItemVO::getCount).sum());
        return respVO;
    }

}
