package com.njcn.rdms.module.system.api.permission;

import com.njcn.rdms.framework.common.enums.CommonStatusEnum;
import com.njcn.rdms.framework.common.pojo.CommonResult;
import com.njcn.rdms.module.system.api.permission.dto.ObjectMenuRespDTO;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRolePermissionRespDTO;
import com.njcn.rdms.module.system.api.permission.dto.ObjectRoleRespDTO;
import com.njcn.rdms.module.system.dal.dataobject.permission.MenuDO;
import com.njcn.rdms.module.system.dal.dataobject.permission.RoleDO;
import com.njcn.rdms.module.system.service.permission.PermissionService;
import com.njcn.rdms.module.system.service.permission.RoleService;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Primary;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

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

import static com.njcn.rdms.framework.common.pojo.CommonResult.success;

@RestController
@Validated
@Primary
@Hidden
public class ObjectPermissionApiImpl implements ObjectPermissionApi {

    @Resource
    private RoleService roleService;
    @Resource
    private PermissionService permissionService;

    @Override
    public CommonResult<ObjectRoleRespDTO> getObjectRoleById(Long roleId, String scopeType, String objectType) {
        return success(convertRole(roleService.getRole(roleId, scopeType, objectType)));
    }

    @Override
    public CommonResult<ObjectRoleRespDTO> getObjectRoleByCode(String roleCode, String scopeType, String objectType) {
        return success(convertRole(roleService.getRoleByCode(roleCode, scopeType, objectType)));
    }

    @Override
    public CommonResult<List<ObjectRoleRespDTO>> getObjectRoleList(Collection<Long> roleIds, String scopeType, String objectType) {
        List<RoleDO> roles = roleService.getRoleList(roleIds, scopeType, objectType);
        return success(roles.stream().map(this::convertRole).toList());
    }

    @Override
    public CommonResult<Set<String>> getObjectRolePermissions(Long roleId, String scopeType, String objectType) {
        RoleDO role = getEnabledScopedRole(roleId, scopeType, objectType);
        if (role == null) {
            return success(Collections.emptySet());
        }
        return success(new LinkedHashSet<>(permissionService.getScopedPermissionsByRoleId(roleId, scopeType, objectType)));
    }

    @Override
    public CommonResult<ObjectRolePermissionRespDTO> getObjectRolePermissionDetail(Long roleId, String scopeType, String objectType) {
        RoleDO role = getEnabledScopedRole(roleId, scopeType, objectType);
        if (role == null) {
            return success(emptyPermissionDetail());
        }

        ObjectRolePermissionRespDTO detail = new ObjectRolePermissionRespDTO();
        detail.setCurrentRole(convertRole(role));
        detail.setMenus(permissionService.getScopedMenusByRoleId(roleId, scopeType, objectType)
                .stream()
                .map(this::convertMenu)
                .toList());
        detail.setPermissions(new LinkedHashSet<>(
                permissionService.getScopedPermissionsByRoleId(roleId, scopeType, objectType)));
        return success(detail);
    }

    @Override
    public CommonResult<ObjectRolePermissionRespDTO> getObjectRolePermissionDetailMerged(
            Collection<Long> roleIds, String scopeType, String objectType) {
        if (roleIds == null || roleIds.isEmpty()) {
            return success(emptyPermissionDetail());
        }

        // 拿全部启用的角色，过滤 null 和未启用
        List<RoleDO> activeRoles = roleIds.stream()
                .distinct()
                .map(id -> getEnabledScopedRole(id, scopeType, objectType))
                .filter(r -> r != null)
                .toList();
        if (activeRoles.isEmpty()) {
            return success(emptyPermissionDetail());
        }

        // 主角色：按 sort 升序，决胜按 id 升序
        Comparator<RoleDO> rolePriority = Comparator
                .comparingInt((RoleDO r) -> r.getSort() == null ? Integer.MAX_VALUE : r.getSort())
                .thenComparingLong(RoleDO::getId);
        RoleDO primaryRole = activeRoles.stream().min(rolePriority).orElseThrow();

        // 非主角色名（按 sort 升序保持稳定顺序）
        List<String> additionalRoleNames = activeRoles.stream()
                .filter(r -> !r.getId().equals(primaryRole.getId()))
                .sorted(rolePriority)
                .map(RoleDO::getName)
                .toList();

        // 菜单 union（按 menu.id 去重，按 menu.sort 排序）
        Map<Long, MenuDO> mergedMenus = new LinkedHashMap<>();
        for (RoleDO role : activeRoles) {
            for (MenuDO menu : permissionService.getScopedMenusByRoleId(role.getId(), scopeType, objectType)) {
                mergedMenus.putIfAbsent(menu.getId(), menu);
            }
        }
        List<ObjectMenuRespDTO> menus = mergedMenus.values().stream()
                .sorted(Comparator.comparingInt(m -> m.getSort() == null ? Integer.MAX_VALUE : m.getSort()))
                .map(this::convertMenu)
                .toList();

        // 权限码 union（LinkedHashSet 保持稳定顺序）
        Set<String> permissions = new LinkedHashSet<>();
        for (RoleDO role : activeRoles) {
            permissions.addAll(permissionService.getScopedPermissionsByRoleId(role.getId(), scopeType, objectType));
        }

        ObjectRolePermissionRespDTO detail = new ObjectRolePermissionRespDTO();
        detail.setCurrentRole(convertRole(primaryRole));
        detail.setAdditionalRoleNames(additionalRoleNames);
        detail.setMenus(menus);
        detail.setPermissions(permissions);
        return success(detail);
    }

    private ObjectRolePermissionRespDTO emptyPermissionDetail() {
        ObjectRolePermissionRespDTO detail = new ObjectRolePermissionRespDTO();
        detail.setCurrentRole(null);
        detail.setMenus(Collections.emptyList());
        detail.setPermissions(Collections.emptySet());
        return detail;
    }

    private RoleDO getEnabledScopedRole(Long roleId, String scopeType, String objectType) {
        RoleDO role = roleService.getRole(roleId, scopeType, objectType);
        if (role == null || !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())) {
            return null;
        }
        return role;
    }

    private ObjectRoleRespDTO convertRole(RoleDO role) {
        if (role == null) {
            return null;
        }
        ObjectRoleRespDTO dto = new ObjectRoleRespDTO();
        dto.setId(role.getId());
        dto.setCode(role.getCode());
        dto.setName(role.getName());
        dto.setScopeType(role.getScopeType());
        dto.setObjectType(role.getObjectType());
        return dto;
    }

    private ObjectMenuRespDTO convertMenu(MenuDO menu) {
        ObjectMenuRespDTO dto = new ObjectMenuRespDTO();
        dto.setId(menu.getId());
        dto.setName(menu.getName());
        dto.setPermission(menu.getPermission());
        dto.setType(menu.getType());
        dto.setSort(menu.getSort());
        dto.setPath(menu.getPath());
        dto.setIcon(menu.getIcon());
        dto.setVisible(menu.getVisible());
        return dto;
    }

}
