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

import com.njcn.rdms.framework.common.pojo.PageParam;
import com.njcn.rdms.framework.common.pojo.PageResult;
import com.njcn.rdms.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.njcn.rdms.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.rdms.module.project.constant.ObjectRoleConstants;
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.controller.admin.project.project.vo.myproject.MyProjectOwnedRespVO;
import com.njcn.rdms.module.project.controller.admin.project.project.vo.myproject.MyProjectPageReqVO;
import com.njcn.rdms.module.project.controller.admin.project.project.vo.myproject.MyProjectParticipatedRespVO;
import com.njcn.rdms.module.project.dal.dataobject.member.UserObjectRoleDO;
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
import com.njcn.rdms.module.project.dal.dataobject.status.ObjectStatusModelDO;
import com.njcn.rdms.module.project.dal.mysql.member.UserObjectRoleMapper;
import com.njcn.rdms.module.project.dal.mysql.project.ProjectMapper;
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.system.api.permission.ObjectPermissionApi;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import com.njcn.rdms.module.system.api.user.AdminUserApi;
import com.njcn.rdms.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
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 MyProjectServiceImpl implements MyProjectService {

    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private ProjectTaskMapper projectTaskMapper;
    @Resource
    private ProjectExecutionMapper projectExecutionMapper;
    @Resource
    private UserObjectRoleMapper userObjectRoleMapper;
    @Resource
    private ObjectStatusModelMapper objectStatusModelMapper;
    @Resource
    private ObjectPermissionApi objectPermissionApi;
    @Resource
    private AdminUserApi adminUserApi;

    /** 工作台「我的项目」列表统一排序：按项目创建时间升序（先创建的在前），id 兜底保证稳定。 */
    private static final Comparator<ProjectDO> PROJECT_CREATE_TIME_ASC =
            Comparator.comparing(ProjectDO::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()))
                    .thenComparing(ProjectDO::getId);

    @Override
    public PageResult<MyProjectParticipatedRespVO> getMyParticipatedPage(MyProjectPageReqVO reqVO) {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        // 1. 我参与的所有 active 角色行（含 manager/dev 等多角色，objectId=项目id）
        List<UserObjectRoleDO> myRoles = userObjectRoleMapper
                .selectActiveListByObjectTypeAndUserId(ProjectObjectConstants.OBJECT_TYPE, loginUserId);
        if (myRoles.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        // 2. 按项目分组我的角色行
        Map<Long, List<UserObjectRoleDO>> rolesByProject = myRoles.stream()
                .filter(r -> r.getObjectId() != null)
                .collect(Collectors.groupingBy(UserObjectRoleDO::getObjectId, LinkedHashMap::new, Collectors.toList()));
        Set<Long> projectIds = new LinkedHashSet<>(rolesByProject.keySet());
        // 3. 项目基本信息
        List<ProjectDO> projects = projectMapper.selectBatchIds(projectIds);
        if (projects.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        // 3.1 仅保留非终态项目（终态项目不在工作台「我的项目」体现），并按创建时间升序（先创建的在前）
        List<String> projectTerminal = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectObjectConstants.OBJECT_TYPE);
        projects = projects.stream()
                .filter(p -> !projectTerminal.contains(p.getStatusCode()))
                .sorted(PROJECT_CREATE_TIME_ASC)
                .collect(Collectors.toList());
        if (projects.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        // 4. statusName 批量回填
        Map<String, String> statusNameMap = loadStatusNameMap(ProjectObjectConstants.OBJECT_TYPE);
        // 5. 角色名 map（一次性拉全部涉及 roleId）
        Map<Long, ObjectRoleRespDTO> roleMap = loadRoleMap(myRoles.stream()
                .map(UserObjectRoleDO::getRoleId).collect(Collectors.toSet()));
        // 5.1 每个项目下"我的可见角色行"：剔除 visible=0 的隐式角色（创建者 / 隐式观察者等业务自动赋予角色）。
        //     若某项目下我没有任何可见角色，则不算"我参与的项目"，整项剔除——与 ProjectMemberServiceImpl 团队列表口径一致。
        Map<Long, List<UserObjectRoleDO>> visibleRolesByProject = new LinkedHashMap<>();
        rolesByProject.forEach((pid, rows) -> {
            List<UserObjectRoleDO> visible = filterVisibleRoleRows(rows, roleMap);
            if (!visible.isEmpty()) {
                visibleRolesByProject.put(pid, visible);
            }
        });
        // 6. 我负责的任务计数（owner=me，按项目分组 total + pending）
        List<String> taskTerminal = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE);
        Map<Long, long[]> taskCountMap = new LinkedHashMap<>();
        for (Map<String, Object> row : projectTaskMapper
                .selectMyTaskCountGroupByProjectIds(loginUserId, projectIds, taskTerminal)) {
            taskCountMap.put(asLong(row.get("projectId")),
                    new long[]{asLong(row.get("totalCount")), asLong(row.get("pendingCount"))});
        }
        // 7. 组装（仅保留我有可见角色的项目）
        List<MyProjectParticipatedRespVO> all = projects.stream()
                .filter(p -> visibleRolesByProject.containsKey(p.getId()))
                .map(p -> {
            MyProjectParticipatedRespVO vo = new MyProjectParticipatedRespVO();
            vo.setId(p.getId());
            vo.setName(p.getProjectName());
            vo.setCode(p.getProjectCode());
            vo.setStatusCode(p.getStatusCode());
            vo.setStatusName(statusNameMap.get(p.getStatusCode()));
            vo.setProgress(toProgressInt(p.getProgressRate()));
            vo.setMyRole(buildMyRole(visibleRolesByProject.get(p.getId()), roleMap));
            long[] c = taskCountMap.getOrDefault(p.getId(), new long[]{0L, 0L});
            vo.setMyTaskCount((int) c[0]);
            vo.setMyPendingTaskCount((int) c[1]);
            return vo;
        }).collect(Collectors.toList());
        return paginate(all, reqVO);
    }

    // ======================== 共用私有方法 ========================

    private Map<String, String> loadStatusNameMap(String objectType) {
        return objectStatusModelMapper.selectListByObjectTypeEnabled(objectType).stream()
                .collect(Collectors.toMap(ObjectStatusModelDO::getStatusCode,
                        ObjectStatusModelDO::getStatusName, (a, b) -> a));
    }

    private Map<Long, ObjectRoleRespDTO> loadRoleMap(Set<Long> roleIds) {
        if (roleIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<ObjectRoleRespDTO> roles = objectPermissionApi
                .getObjectRoleList(roleIds, ObjectRoleConstants.ROLE_SCOPE_OBJECT, ProjectObjectConstants.OBJECT_TYPE)
                .getCheckedData();
        if (roles == null || roles.isEmpty()) {
            return Collections.emptyMap();
        }
        return roles.stream().collect(Collectors.toMap(ObjectRoleRespDTO::getId, Function.identity(), (a, b) -> a));
    }

    /** 可见角色行：剔除 visible=0 的隐式角色（创建者 / 隐式观察者等业务自动赋予角色）；visible=null 或 roleMap 缺失视同可见。 */
    private List<UserObjectRoleDO> filterVisibleRoleRows(List<UserObjectRoleDO> rows, Map<Long, ObjectRoleRespDTO> roleMap) {
        if (rows == null || rows.isEmpty()) {
            return Collections.emptyList();
        }
        return rows.stream()
                .filter(r -> {
                    ObjectRoleRespDTO role = roleMap.get(r.getRoleId());
                    return role == null || !Integer.valueOf(0).equals(role.getVisible());
                })
                .collect(Collectors.toList());
    }

    /**
     * 主角色 + 附加角色名拼接。入参为已过滤的可见角色行（visible=0 隐式角色已在上游剔除）。
     * 主角色挑选与 ProjectMemberServiceImpl 一致：MANAGER 优先，否则 roleId 最小。
     */
    private String buildMyRole(List<UserObjectRoleDO> rowsVisible, Map<Long, ObjectRoleRespDTO> roleMap) {
        if (rowsVisible == null || rowsVisible.isEmpty()) {
            return null;
        }
        UserObjectRoleDO primary = rowsVisible.stream()
                .filter(r -> {
                    ObjectRoleRespDTO role = roleMap.get(r.getRoleId());
                    return role != null && Objects.equals(ProjectObjectConstants.MANAGER_ROLE_CODE, role.getCode());
                })
                .findFirst()
                .orElseGet(() -> rowsVisible.stream()
                        .min(Comparator.comparing(UserObjectRoleDO::getRoleId))
                        .orElse(rowsVisible.get(0)));
        String primaryName = roleName(roleMap, primary.getRoleId());
        List<String> additional = rowsVisible.stream()
                .filter(r -> !Objects.equals(r.getId(), primary.getId()))
                .map(r -> roleName(roleMap, r.getRoleId()))
                .filter(Objects::nonNull)
                .sorted()
                .collect(Collectors.toList());
        StringBuilder sb = new StringBuilder(primaryName == null ? "" : primaryName);
        for (String n : additional) {
            if (sb.length() > 0) {
                sb.append(" / ");
            }
            sb.append(n);
        }
        return sb.length() == 0 ? null : sb.toString();
    }

    private String roleName(Map<Long, ObjectRoleRespDTO> roleMap, Long roleId) {
        ObjectRoleRespDTO role = roleMap.get(roleId);
        return role == null ? null : role.getName();
    }

    private Integer toProgressInt(BigDecimal v) {
        return v == null ? 0 : v.setScale(0, RoundingMode.HALF_UP).intValue();
    }

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

    private <T> PageResult<T> paginate(List<T> all, PageParam reqVO) {
        long total = all.size();
        Integer pageSize = reqVO.getPageSize();
        if (pageSize == null || pageSize < 0) {
            return new PageResult<>(all, total);
        }
        int pageNo = reqVO.getPageNo() == null || reqVO.getPageNo() < 1 ? 1 : reqVO.getPageNo();
        int fromIndex = Math.min((pageNo - 1) * pageSize, all.size());
        int toIndex = Math.min(fromIndex + pageSize, all.size());
        return new PageResult<>(all.subList(fromIndex, toIndex), total);
    }

    @Override
    public PageResult<MyProjectOwnedRespVO> getMyOwnedPage(MyProjectPageReqVO reqVO) {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        // 1. 我负责的项目（managerUserId = 登录用户）
        List<ProjectDO> projects = projectMapper.selectList(new LambdaQueryWrapperX<ProjectDO>()
                .eq(ProjectDO::getManagerUserId, loginUserId));
        if (projects.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        // 1.1 仅保留非终态项目（终态项目不在工作台「我的项目」体现），并按创建时间升序（先创建的在前）
        List<String> projectTerminal = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectObjectConstants.OBJECT_TYPE);
        projects = projects.stream()
                .filter(p -> !projectTerminal.contains(p.getStatusCode()))
                .sorted(PROJECT_CREATE_TIME_ASC)
                .collect(Collectors.toList());
        if (projects.isEmpty()) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        Set<Long> projectIds = projects.stream()
                .map(ProjectDO::getId).collect(Collectors.toCollection(LinkedHashSet::new));
        // 2. 终态集
        List<String> taskTerminal = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectTaskConstants.OBJECT_TYPE);
        List<String> execTerminal = objectStatusModelMapper
                .selectTerminalStatusCodesByObjectTypeEnabled(ProjectExecutionConstants.OBJECT_TYPE);
        LocalDate today = LocalDate.now();
        // 3. 任务数 + 逾期数（一次扫表）
        Map<Long, long[]> taskMap = new LinkedHashMap<>();
        for (Map<String, Object> row : projectTaskMapper
                .selectTaskAndOverdueCountGroupByProjectIds(projectIds, taskTerminal, today)) {
            taskMap.put(asLong(row.get("projectId")),
                    new long[]{asLong(row.get("taskCount")), asLong(row.get("overdueCount"))});
        }
        // 4. 执行数
        Map<Long, Long> execMap = new LinkedHashMap<>();
        for (Map<String, Object> row : projectExecutionMapper
                .selectExecutionCountGroupByProjectIds(projectIds, execTerminal)) {
            execMap.put(asLong(row.get("projectId")), asLong(row.get("executionCount")));
        }
        // 5. 每个负责人(owner)的进行中任务数：projectId -> (ownerId -> count)
        Map<Long, Map<Long, Long>> activeTaskMap = new LinkedHashMap<>();
        for (Map<String, Object> row : projectTaskMapper
                .selectActiveTaskCountGroupByProjectIdAndOwner(projectIds, taskTerminal)) {
            Long pid = asLong(row.get("projectId"));
            Long ownerId = asLong(row.get("ownerId"));
            activeTaskMap.computeIfAbsent(pid, k -> new LinkedHashMap<>())
                    .put(ownerId, asLong(row.get("activeTaskCount")));
        }
        // 6. 成员清单（批量一次拿全，内存按项目分组；同 user 多角色去重为一个成员）
        List<UserObjectRoleDO> memberRows = userObjectRoleMapper
                .selectActiveListByObjectTypeAndObjectIds(ProjectObjectConstants.OBJECT_TYPE, projectIds);
        Map<Long, List<Long>> memberUserIdsByProject = new LinkedHashMap<>();
        for (UserObjectRoleDO m : memberRows) {
            if (m.getObjectId() == null || m.getUserId() == null) {
                continue;
            }
            List<Long> users = memberUserIdsByProject.computeIfAbsent(m.getObjectId(), k -> new ArrayList<>());
            if (!users.contains(m.getUserId())) {
                users.add(m.getUserId());
            }
        }
        // 7. 成员昵称批量回填
        Set<Long> allUserIds = memberUserIdsByProject.values().stream()
                .flatMap(List::stream).collect(Collectors.toSet());
        Map<Long, AdminUserRespDTO> userMap = allUserIds.isEmpty()
                ? Collections.emptyMap() : adminUserApi.getUserMap(allUserIds);
        // 8. myRole 恒为负责人角色名（一次性解析）
        String managerRoleName = resolveManagerRoleName();
        // 9. 组装
        List<MyProjectOwnedRespVO> all = projects.stream().map(p -> {
            MyProjectOwnedRespVO vo = new MyProjectOwnedRespVO();
            vo.setId(p.getId());
            vo.setName(p.getProjectName());
            vo.setCode(p.getProjectCode());
            vo.setProgress(toProgressInt(p.getProgressRate()));
            vo.setMyRole(managerRoleName);
            vo.setPlannedEndDate(p.getPlannedEndDate());
            long[] tc = taskMap.getOrDefault(p.getId(), new long[]{0L, 0L});
            vo.setTaskCount((int) tc[0]);
            vo.setOverdueCount((int) tc[1]);
            vo.setExecutionCount(execMap.getOrDefault(p.getId(), 0L).intValue());
            List<Long> memberUserIds = memberUserIdsByProject.getOrDefault(p.getId(), Collections.emptyList());
            vo.setMemberCount(memberUserIds.size());
            Map<Long, Long> ownerCounts = activeTaskMap.getOrDefault(p.getId(), Collections.emptyMap());
            List<MyProjectOwnedRespVO.MemberLoadVO> members = memberUserIds.stream().map(uid -> {
                MyProjectOwnedRespVO.MemberLoadVO mv = new MyProjectOwnedRespVO.MemberLoadVO();
                mv.setUserId(uid);
                AdminUserRespDTO user = userMap.get(uid);
                mv.setUserName(user == null ? null : user.getNickname());
                mv.setActiveTaskCount(ownerCounts.getOrDefault(uid, 0L).intValue());
                return mv;
            }).collect(Collectors.toList());
            vo.setMembers(members);
            return vo;
        }).collect(Collectors.toList());
        return paginate(all, reqVO);
    }

    /** 项目负责人角色名（对象域 MANAGER_ROLE_CODE）；解析失败返回 null，不阻断列表。 */
    private String resolveManagerRoleName() {
        try {
            ObjectRoleRespDTO role = objectPermissionApi
                    .getObjectRoleByCode(ProjectObjectConstants.MANAGER_ROLE_CODE,
                            ObjectRoleConstants.ROLE_SCOPE_OBJECT, ProjectObjectConstants.OBJECT_TYPE)
                    .getCheckedData();
            return role == null ? null : role.getName();
        } catch (RuntimeException ex) {
            return null;
        }
    }

}
