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

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.system.entity.User;
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.PermissionDTO;
import com.qqchen.deploy.backend.system.model.RoleDTO;
import com.qqchen.deploy.backend.system.model.query.RoleQuery;
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.repository.IUserRepository;
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.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 IUserRepository userRepository;

    @Resource
    private IPermissionService permissionService;

    @Resource
    private IMenuRepository menuRepository;

    @Resource
    private PermissionConverter permissionConverter;

    @Resource
    private IPermissionRepository permissionRepository;

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

    @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
    @Transactional
    public void assignRoles(Long userId, List<Long> roleIds) {
        // 获取用户
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new BusinessException(ResponseCode.USER_NOT_FOUND));

        // 不允许修改admin用户的角色
        if ("admin".equals(user.getUsername())) {
            throw new BusinessException(ResponseCode.ROLE_ADMIN_CANNOT_UPDATE);
        }

        // 获取角色列表
        List<Role> roles = roleRepository.findAllById(roleIds);
        
        // 验证所有角色ID是否都存在
        if (roles.size() != roleIds.size()) {
            throw new BusinessException(ResponseCode.ROLE_NOT_FOUND);
        }

        // 设置用���角色
        user.setRoles(new HashSet<>(roles));
        
        // 保存更新
        userRepository.save(user);
    }

    @Override
    public List<PermissionDTO> listRolePermissions(Long roleId) {
        Role role = roleRepository.findById(roleId)
            .orElseThrow(() -> new BusinessException(ResponseCode.ROLE_NOT_FOUND));

        return role.getPermissions().stream()
            .map(permission -> {
                PermissionDTO dto = permissionConverter.toDto(permission);
                String menuName = menuRepository.findById(permission.getMenuId())
                    .map(Menu::getName)
                    .orElse(null);
                dto.setMenuName(menuName);
                return dto;
            })
            .collect(Collectors.toList());
    }

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

        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);
        roleRepository.save(role);
    }
}