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

import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.project.constant.ProjectTaskConstants;
import com.njcn.rdms.module.project.controller.admin.project.project.vo.workbench.TeamLoadRespVO;
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
import com.njcn.rdms.module.project.dal.mysql.personal.PersonalItemMapper;
import com.njcn.rdms.module.project.dal.mysql.project.ProjectMapper;
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.system.api.user.AdminUserApi;
import com.njcn.rdms.module.system.api.user.UserManagementRelationApi;
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
import com.njcn.rdms.module.system.api.user.dto.UserManagementRelationRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class MyTeamServiceImpl implements MyTeamService {

    /** 临期窗口天数:计划结束 <= 今天 + 3(2026-06-12 前端口径确认)。 */
    private static final int DUE_SOON_DAYS = 3;

    @Resource
    private ProjectTaskMapper projectTaskMapper;
    @Resource
    private PersonalItemMapper personalItemMapper;
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private ObjectStatusModelMapper objectStatusModelMapper;
    @Resource
    private UserManagementRelationApi userManagementRelationApi;
    @Resource
    private AdminUserApi adminUserApi;

    @Override
    public List<TeamMember> resolveTeamMembers() {
        Long me = SecurityFrameworkUtils.getLoginUserId();
        // 管理链路 RPC 不过滤生效期(system 侧直接按 manager 查),这里按 effectiveFrom/Until 过滤当前生效
        List<UserManagementRelationRespDTO> relations = userManagementRelationApi
                .getRelationListByManagerUserId(me).getCheckedData();
        LocalDateTime now = LocalDateTime.now();
        LinkedHashSet<Long> userIds = new LinkedHashSet<>();
        userIds.add(me);
        if (relations != null) {
            relations.stream()
                    .filter(r -> r.getSubordinateUserId() != null)
                    .filter(r -> r.getEffectiveFrom() == null || !r.getEffectiveFrom().isAfter(now))
                    .filter(r -> r.getEffectiveUntil() == null || r.getEffectiveUntil().isAfter(now))
                    .map(UserManagementRelationRespDTO::getSubordinateUserId)
                    .forEach(userIds::add);
        }
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
        return userIds.stream().map(uid -> {
            AdminUserRespDTO user = userMap.get(uid);
            return new TeamMember(uid, user == null ? null : user.getNickname());
        }).collect(Collectors.toList());
    }

    @Override
    public TeamLoadRespVO getTeamLoad() {
        List<TeamMember> members = resolveTeamMembers();
        List<Long> userIds = members.stream().map(TeamMember::userId).collect(Collectors.toList());
        LocalDate today = LocalDate.now();
        LocalDate dueSoonEnd = today.plusDays(DUE_SOON_DAYS);
        // 个人事项状态机复用 task 对象类型,终态同源
        List<String> terminal = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE);
        // 任务:按 (成员, 项目) 分组;个人事项:按成员分组。各一次扫表,无逐人查询
        List<Map<String, Object>> taskRows = projectTaskMapper
                .selectInvolvedLoadStatsByUserIds(userIds, terminal, today, dueSoonEnd);
        List<Map<String, Object>> personalRows = personalItemMapper
                .selectLoadStatsByOwnerIds(userIds, terminal, today, dueSoonEnd);
        // 项目名批量回填
        Set<Long> projectIds = taskRows.stream().map(r -> asLong(r.get("projectId")))
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, ProjectDO> projectMap = projectIds.isEmpty() ? Collections.emptyMap()
                : projectMapper.selectBatchIds(projectIds).stream()
                        .collect(Collectors.toMap(ProjectDO::getId, Function.identity(), (a, b) -> a));
        // 任务行按成员分组
        Map<Long, List<Map<String, Object>>> taskRowsByUser = taskRows.stream()
                .collect(Collectors.groupingBy(r -> asLong(r.get("userId")), LinkedHashMap::new, Collectors.toList()));
        Map<Long, Map<String, Object>> personalRowByUser = personalRows.stream()
                .collect(Collectors.toMap(r -> asLong(r.get("ownerId")), Function.identity(), (a, b) -> a));
        // 组装每个成员
        List<TeamLoadRespVO.MemberVO> memberVOs = members.stream().map(m -> {
            TeamLoadRespVO.MemberVO vo = new TeamLoadRespVO.MemberVO();
            vo.setUserId(m.userId());
            vo.setUserNickname(m.nickname());
            List<TeamLoadRespVO.LoadItemVO> items = new ArrayList<>();
            long dueSoon = 0;
            long overdue = 0;
            for (Map<String, Object> row : taskRowsByUser.getOrDefault(m.userId(), Collections.emptyList())) {
                TeamLoadRespVO.LoadItemVO item = new TeamLoadRespVO.LoadItemVO();
                Long pid = asLong(row.get("projectId"));
                item.setProjectId(pid);
                ProjectDO project = pid == null ? null : projectMap.get(pid);
                item.setProjectName(project == null ? null : project.getProjectName());
                item.setKind("project");
                item.setCount((int) unbox(row.get("taskCount")));
                items.add(item);
                dueSoon += unbox(row.get("dueSoonCount"));
                overdue += unbox(row.get("overdueCount"));
            }
            // 项目行按 count 降序
            items.sort(Comparator.comparing(TeamLoadRespVO.LoadItemVO::getCount,
                    Comparator.reverseOrder()));
            Map<String, Object> personal = personalRowByUser.get(m.userId());
            if (personal != null && unbox(personal.get("itemCount")) > 0) {
                TeamLoadRespVO.LoadItemVO item = new TeamLoadRespVO.LoadItemVO();
                item.setKind("personal");
                item.setCount((int) unbox(personal.get("itemCount")));
                items.add(item); // 个人事项行固定排在项目行之后
                dueSoon += unbox(personal.get("dueSoonCount"));
                overdue += unbox(personal.get("overdueCount"));
            }
            vo.setItems(items);
            vo.setDueSoonCount((int) dueSoon);
            vo.setOverdueCount((int) overdue);
            return vo;
        }).collect(Collectors.toList());
        // members[0] 恒为自己;其余按压力(总未完成+临期+逾期)降序
        TeamLoadRespVO.MemberVO self = memberVOs.get(0);
        List<TeamLoadRespVO.MemberVO> rest = new ArrayList<>(memberVOs.subList(1, memberVOs.size()));
        rest.sort(Comparator.comparingLong(MyTeamServiceImpl::pressure).reversed());
        List<TeamLoadRespVO.MemberVO> ordered = new ArrayList<>();
        ordered.add(self);
        ordered.addAll(rest);
        TeamLoadRespVO resp = new TeamLoadRespVO();
        resp.setMembers(ordered);
        return resp;
    }

    private static long pressure(TeamLoadRespVO.MemberVO vo) {
        long total = vo.getItems().stream().mapToLong(TeamLoadRespVO.LoadItemVO::getCount).sum();
        return total + vo.getDueSoonCount() + vo.getOverdueCount();
    }

    private static Long asLong(Object v) {
        return v == null ? null : ((Number) v).longValue();
    }

    private static long unbox(Object v) {
        return v == null ? 0L : ((Number) v).longValue();
    }

}
