package com.qqchen.deploy.backend.system.service.impl;

import com.qqchen.deploy.backend.system.converter.MenuConverter;
import com.qqchen.deploy.backend.system.converter.PermissionConverter;
import com.qqchen.deploy.backend.system.entity.Menu;
import com.qqchen.deploy.backend.system.entity.Permission;
import com.qqchen.deploy.backend.system.entity.Role;
import com.qqchen.deploy.backend.system.entity.RoleTag;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.UniqueConstraintException;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.system.model.MenuDTO;
import com.qqchen.deploy.backend.system.model.PermissionDTO;
import com.qqchen.deploy.backend.system.model.RoleDTO;
import com.qqchen.deploy.backend.system.model.query.RoleQuery;
import com.qqchen.deploy.backend.system.model.response.RoleMenusAndPermissionsResponse;
import com.qqchen.deploy.backend.system.repository.IMenuRepository;
import com.qqchen.deploy.backend.system.repository.IPermissionRepository;
import com.qqchen.deploy.backend.system.repository.IRoleRepository;
import com.qqchen.deploy.backend.system.repository.IRoleTagRepository;
import com.qqchen.deploy.backend.system.service.IRoleService;
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
import com.qqchen.deploy.backend.system.service.IPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.qqchen.deploy.backend.framework.annotation.ServiceType.Type.DATABASE;

@Slf4j
@Service
@ServiceType(DATABASE)
public class RoleServiceImpl extends BaseServiceImpl<Role, RoleDTO, RoleQuery, Long> implements IRoleService {

    @Resource
    private IRoleRepository roleRepository;

    @Resource
    private IRoleTagRepository roleTagRepository;

    @Resource
    private IPermissionService permissionService;

    @Resource
    private IMenuRepository menuRepository;

    @Resource
    private PermissionConverter permissionConverter;

    @Resource
    private MenuConverter menuConverter;

    @Resource
    private IPermissionRepository permissionRepository;

    @Override
    public List<Long> getUserRoleIds(Long userId) {
        return roleRepository.findRoleIdsByUserId(userId);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        // 检查是否是超级管理员角色
        Role role = roleRepository.findById(id)
            .orElseThrow(() -> new BusinessException(ResponseCode.ROLE_NOT_FOUND));

        if (Boolean.TRUE.equals(role.getIsAdmin())) {
            throw new BusinessException(ResponseCode.ROLE_ADMIN_CANNOT_DELETE);
        }

        // 调用父类的删除方法
        super.delete(id);
    }

    @Override
    public void validateCode(String code) {
        if (roleRepository.existsByCodeAndDeletedFalse(code)) {
            throw new BusinessException(ResponseCode.ROLE_CODE_EXISTS);
        }
    }

    @Override
    public void validateName(String name) {
        if (roleRepository.existsByNameAndDeletedFalse(name)) {
            throw new BusinessException(ResponseCode.ROLE_NAME_EXISTS);
        }
    }

    @Override
    protected void validateUniqueConstraints(RoleDTO dto) {
        // 检查角色编码唯一性
        if (roleRepository.existsByCodeAndDeletedFalse(dto.getCode())) {
            throw new UniqueConstraintException(ResponseCode.ROLE_CODE_EXISTS, "code", dto.getCode());
        }

        // 检查角色名称唯一性
        if (roleRepository.existsByNameAndDeletedFalse(dto.getName())) {
            throw new UniqueConstraintException(ResponseCode.ROLE_NAME_EXISTS, "name", dto.getName());
        }
    }

    @Override
    @Transactional
    public void assignTags(Long roleId, List<Long> tagIds) {
        Role role = findEntityById(roleId);
        // 先清除原有关系
        role.getTags().clear();
        // 设置新的关系
        Set<RoleTag> tags = roleTagRepository.findAllById(tagIds)
            .stream()
            .collect(Collectors.toSet());
        role.setTags(tags);
        roleRepository.save(role);
    }

    @Override
    public RoleMenusAndPermissionsResponse getRoleMenusAndPermissions(Long roleId) {
        Role role = roleRepository.findById(roleId)
            .orElseThrow(() -> new BusinessException(ResponseCode.ROLE_NOT_FOUND));

        // 获取菜单ID列表
        List<Long> menuIds = role.getMenus().stream()
            .map(Menu::getId)
            .sorted()
            .collect(Collectors.toList());

        // 获取功能权限点ID列表
        List<Long> permissionIds = role.getPermissions().stream()
            .map(Permission::getId)
            .sorted()
            .collect(Collectors.toList());

        return new com.qqchen.deploy.backend.system.model.response.RoleMenusAndPermissionsResponse(menuIds, permissionIds);
    }

    @Override
    @Transactional
    public void assignMenusAndPermissions(Long roleId, List<Long> menuIds, List<Long> permissionIds) {
        Role role = roleRepository.findById(roleId)
            .orElseThrow(() -> new BusinessException(ResponseCode.ROLE_NOT_FOUND));

        // 1. 处理菜单维度：自动补全父菜单
        if (menuIds != null && !menuIds.isEmpty()) {
            // 一次性查询所有菜单，避免N+1查询
            List<Menu> allMenus = menuRepository.findByDeletedFalseOrderBySort();
            Map<Long, Menu> menuMap = allMenus.stream()
                .collect(Collectors.toMap(Menu::getId, menu -> menu));
            
            // 验证请求的菜单是否存在
            for (Long menuId : menuIds) {
                if (!menuMap.containsKey(menuId)) {
                    throw new BusinessException(ResponseCode.DATA_NOT_FOUND);
                }
            }
            
            // 在内存中递归补全父菜单ID
            Set<Long> completeMenuIds = new HashSet<>(menuIds);
            for (Long menuId : menuIds) {
                addParentMenuIdsFromMap(completeMenuIds, menuId, menuMap);
            }
            
            // 根据补全后的ID获取菜单对象
            Set<Menu> menus = completeMenuIds.stream()
                .map(menuMap::get)
                .filter(menu -> menu != null)
                .collect(Collectors.toSet());
            
            role.setMenus(menus);
            
            log.info("角色[{}]分配菜单完成，原始菜单数：{}，补全后菜单数：{}", 
                roleId, menuIds.size(), completeMenuIds.size());
        } else {
            role.setMenus(new HashSet<>());
        }

        // 2. 处理功能权限点维度
        if (permissionIds != null && !permissionIds.isEmpty()) {
            Set<Permission> permissions = permissionRepository.findByIdIn(permissionIds)
                .stream()
                .collect(Collectors.toSet());
            
            if (permissions.size() != permissionIds.size()) {
                throw new BusinessException(ResponseCode.PERMISSION_NOT_FOUND);
            }
            
            role.setPermissions(permissions);
            log.info("角色[{}]分配功能权限完成，权限点数：{}", roleId, permissionIds.size());
        } else {
            role.setPermissions(new HashSet<>());
        }
        
        roleRepository.save(role);
    }

    /**
     * 在内存中递归添加所有父菜单ID（优化版，避免数据库查询）
     * @param menuIds 菜单ID集合
     * @param menuId 当前菜单ID
     * @param menuMap 所有菜单的Map
     */
    private void addParentMenuIdsFromMap(Set<Long> menuIds, Long menuId, Map<Long, Menu> menuMap) {
        Menu menu = menuMap.get(menuId);
        if (menu != null && menu.getParentId() != null) {
            menuIds.add(menu.getParentId());
            // 递归查找父菜单的父菜单
            addParentMenuIdsFromMap(menuIds, menu.getParentId(), menuMap);
        }
    }
}