package com.yunhai.userbase.service.push;
import com.yunhai.userbase.entity.SysGroup;
import com.yunhai.userbase.entity.SysUser;
import com.yunhai.userbase.entity.SysUserGroupRel;
import com.yunhai.userbase.enums.GroupTypeEnum;
import com.yunhai.userbase.enums.StatusEnum;
import com.yunhai.userbase.model.push.dto.PushGroupDTO;
import com.yunhai.userbase.model.push.dto.PushUserDTO;
import com.yunhai.userbase.repository.SysGroupRepository;
import com.yunhai.userbase.repository.SysUserGroupRelRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
/**
* 领域模型 → 文档契约 DTO 的装配器。
* 关键映射(方案 v5 §2 / 文档 3.x):
*
* - 组 type:GroupTypeEnum.key 直接透传(1-8 零映射)
* - 用户 status:NORMAL(0)→0正常 / DISABLED(1)→2禁用
* - groups[].schoolId:组所属学校范围 id(沿 parentId 向上最近 SCHOOL_GROUP)
* - roleList[].schId:用户主组所属学校范围 id(userbase 无角色-学校关联,统一取主校)
*
*
* @author chenx
* @date 2026/8/14
*/
@Service
public class PushPayloadAssembler {
private static final int ROOT_PARENT_ID = 0;
private static final int IS_MAIN = 1;
@Autowired
private SysGroupRepository sysGroupRepository;
@Autowired
private SysUserGroupRelRepository sysUserGroupRelRepository;
@Autowired
private GroupScopeHelper groupScopeHelper;
// ===================== 组 =====================
/** 组节点(不含 children)。AddGroup / UpdateGroup 使用。 */
public PushGroupDTO toGroupDto(SysGroup g) {
if (g == null) {
return null;
}
PushGroupDTO d = new PushGroupDTO();
d.setId(g.getId());
d.setName(g.getName());
// 文档 code 为「机构代码」,userbase 的 sys_group 无此属性,按可选项留空(序列化后为 null)
d.setType(g.getType() == null ? null : g.getType().getKey());
d.setPid(g.getParentId());
d.setNo(g.getSort());
return d;
}
/** 组节点 + 递归 children(SyncGroup 使用)。 */
public PushGroupDTO toGroupDtoWithChildren(SysGroup g, Map> childrenMap) {
PushGroupDTO d = toGroupDto(g);
List children = childrenMap.get(g.getId());
if (children != null) {
d.setChildren(children.stream()
.map(c -> toGroupDtoWithChildren(c, childrenMap))
.collect(Collectors.toList()));
}
return d;
}
/** 多个组(AddGroup / UpdateGroup),无 children,带 pid。 */
public List toGroupDtoList(List groups) {
if (groups == null) {
return Collections.emptyList();
}
return groups.stream().map(this::toGroupDto).collect(Collectors.toList());
}
// ===================== 用户 =====================
/** 单个用户 → PushUserDTO(含 groups / roleList,学校 id 已解析)。 */
public PushUserDTO toUserDto(SysUser u) {
if (u == null) {
return null;
}
PushUserDTO d = new PushUserDTO();
d.setId(u.getId());
d.setAccount(u.getAccount());
d.setName(u.getRealName());
d.setIdcard(u.getIdcard());
d.setPhone(u.getPhone());
d.setEmail(u.getEmail());
d.setGender(u.getGender());
d.setBirthday(u.getBirthday() == null ? null : u.getBirthday().toString());
// status:NORMAL(0)→0正常 / DISABLED(1)→2禁用
d.setStatus(u.getDisabled() == StatusEnum.NORMAL ? 0 : 2);
d.setProfilePicture(u.getProfilePicture());
List rels = sysUserGroupRelRepository.findByUserId(u.getId());
Integer mainSchoolId = resolveMainSchoolId(rels);
// groups
List groupRefs = new ArrayList<>();
for (SysUserGroupRel rel : rels) {
PushUserDTO.PushUserGroupRef ref = new PushUserDTO.PushUserGroupRef();
ref.setGroupId(rel.getGroupId());
ref.setNo(rel.getSortNo());
ref.setSchoolId(groupScopeHelper.resolveSchoolId(rel.getGroupId()));
groupRefs.add(ref);
}
d.setGroups(groupRefs);
// roleList:每个 roleId 一行,schId 取主组学校(userbase 无角色-学校关联)
List roleRefs = new ArrayList<>();
if (u.getRoles() != null) {
for (Integer roleId : u.getRoles()) {
PushUserDTO.PushUserRoleRef ref = new PushUserDTO.PushUserRoleRef();
ref.setRoleId(roleId);
ref.setSchId(mainSchoolId);
roleRefs.add(ref);
}
}
d.setRoleList(roleRefs);
return d;
}
/** 多个用户(AddUser / UpdateUser / SyncUser)。 */
public List toUserDtoList(List users) {
if (users == null) {
return Collections.emptyList();
}
return users.stream().map(this::toUserDto).collect(Collectors.toList());
}
/** 取用户主组(isMain=1,否则首个关联)所属学校范围 id。 */
private Integer resolveMainSchoolId(List rels) {
if (rels == null || rels.isEmpty()) {
return null;
}
Integer mainGroupId = rels.stream()
.filter(r -> r.getIsMain() != null && r.getIsMain() == IS_MAIN)
.map(SysUserGroupRel::getGroupId)
.findFirst()
.orElse(rels.get(0).getGroupId());
return groupScopeHelper.resolveSchoolId(mainGroupId);
}
// ===================== 公共工具 =====================
/** 构建 parentId → 直接子节点列表(null 视为根 0),同层按 sort / id 升序。 */
public Map> buildChildrenMap(List all) {
Map> childrenMap = new HashMap<>();
for (SysGroup g : all) {
Integer key = (g.getParentId() == null) ? ROOT_PARENT_ID : g.getParentId();
childrenMap.computeIfAbsent(key, k -> new ArrayList<>()).add(g);
}
Comparator order = (a, b) -> {
int sa = a.getSort() == null ? 999 : a.getSort();
int sb = b.getSort() == null ? 999 : b.getSort();
if (sa != sb) {
return Integer.compare(sa, sb);
}
return Integer.compare(a.getId(), b.getId());
};
for (List siblings : childrenMap.values()) {
siblings.sort(order);
}
return childrenMap;
}
/** 构建整棵组树(从根 pid=0 起),SyncGroup 全量同步入口。 */
public List buildFullGroupTree() {
List all = sysGroupRepository.findAll();
if (all.isEmpty()) {
return Collections.emptyList();
}
Map> childrenMap = buildChildrenMap(all);
List roots = childrenMap.getOrDefault(ROOT_PARENT_ID, new ArrayList<>());
return roots.stream()
.map(r -> toGroupDtoWithChildren(r, childrenMap))
.collect(Collectors.toList());
}
}