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

import com.njcn.rdms.module.project.constant.ObjectRoleConstants;
import com.njcn.rdms.module.project.controller.admin.common.vo.CurrentUserRoleVO;
import com.njcn.rdms.module.project.dal.dataobject.member.UserObjectRoleDO;
import com.njcn.rdms.module.project.dal.mysql.member.UserObjectRoleMapper;
import com.njcn.rdms.module.system.api.permission.ObjectPermissionApi;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
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;

/**
 * 批量解析「当前登录用户在一批同类型对象上担任的角色」。
 *
 * <p>供产品列表、项目列表等顶层主列表复用：对当前页只做两次额外查询
 *（角色行一次、角色名翻译一次），无 N+1。返回结果<strong>不做任何可见性过滤</strong>——
 * 创建者 / 隐式观察者等业务自动赋予角色也会返回（口径见
 * docs/superpowers/specs/2026-06-17-列表当前用户角色-design.md），因此不读 {@code visible}。
 */
@Component
public class CurrentUserRoleResolver {

    @Resource
    private UserObjectRoleMapper userObjectRoleMapper;
    @Resource
    private ObjectPermissionApi objectPermissionApi;

    /**
     * @param objectType      对象类型（product / project）
     * @param userId          当前登录用户编号
     * @param objectIds       当前页对象编号集合
     * @param managerRoleCode 该对象类型的经理角色编码，用于排序时把经理置顶
     * @return objectId -&gt; 角色列表（稳定顺序：经理优先，其余按 roleId 升序）；
     *         无角色的对象不在返回 map 中，调用方按空数组处理
     */
    public Map<Long, List<CurrentUserRoleVO>> resolveByObjectIds(
            String objectType, Long userId, Collection<Long> objectIds, String managerRoleCode) {
        if (userId == null || objectIds == null || objectIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<UserObjectRoleDO> rows = userObjectRoleMapper
                .selectActiveListByObjectTypeAndUserIdAndObjectIds(objectType, userId, objectIds);
        if (rows.isEmpty()) {
            return Collections.emptyMap();
        }
        // 一次性翻译涉及的角色（roleId -> code/name），避免逐对象翻译
        Set<Long> roleIds = rows.stream().map(UserObjectRoleDO::getRoleId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, ObjectRoleRespDTO> roleMap = loadRoleMap(roleIds, objectType);
        // 稳定排序：经理角色置顶，其余按 roleId 升序，避免每次返回顺序漂移
        Comparator<ObjectRoleRespDTO> order = Comparator
                .comparingInt((ObjectRoleRespDTO d) -> Objects.equals(managerRoleCode, d.getCode()) ? 0 : 1)
                .thenComparing(ObjectRoleRespDTO::getId, Comparator.nullsLast(Comparator.naturalOrder()));
        return rows.stream()
                .filter(r -> r.getObjectId() != null && roleMap.containsKey(r.getRoleId()))
                .collect(Collectors.groupingBy(UserObjectRoleDO::getObjectId))
                .entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream()
                        .map(r -> roleMap.get(r.getRoleId()))
                        .sorted(order)
                        .map(this::toVO)
                        .collect(Collectors.toList())));
    }

    private CurrentUserRoleVO toVO(ObjectRoleRespDTO dto) {
        CurrentUserRoleVO vo = new CurrentUserRoleVO();
        vo.setRoleKey(dto.getCode());
        vo.setRoleName(dto.getName());
        return vo;
    }

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

}
