package com.github.starhq.app.service.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.starhq.app.dto.security.RoleAuthority;
import com.github.starhq.app.dto.user.ResetPasswordDto;
import com.github.starhq.app.dto.user.UserDto;
import com.github.starhq.app.entity.DefaultRole;
import com.github.starhq.app.entity.Role;
import com.github.starhq.app.entity.User;
import com.github.starhq.app.entity.UserRole;
import com.github.starhq.app.entity.enums.UserStatus;
import com.github.starhq.app.exception.BusinessException;
import com.github.starhq.app.exception.DuplicateException;
import com.github.starhq.app.mappper.DefaultRoleMapper;
import com.github.starhq.app.mappper.RoleMapper;
import com.github.starhq.app.mappper.UserMapper;
import com.github.starhq.app.mappper.UserRoleMapper;
import com.github.starhq.app.service.AuthService;

import lombok.RequiredArgsConstructor;

@Service("authService")
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final UserMapper userMapper;
    private final RoleMapper roleMapper;
    private final UserRoleMapper userRoleMapper;
    private final DefaultRoleMapper defaultRoleMapper;
    private final PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = userMapper.selectOne(queryWrapper);
        if (Objects.isNull(user)) {
            throw new BadCredentialsException("error.user.login.fail");
        }
        if (!Objects.equals(UserStatus.ACTIVE, user.getStatus())) {
            throw new DisabledException("error.user.login.disabled");
        }
        List<Role> roles = roleMapper.selectAssignedRolesByUserId(user.getId());
        if (CollectionUtils.isEmpty(roles)) {
            throw new AccessDeniedException("error.user.login.no_roles");
        }
        Set<RoleAuthority> authorities = new HashSet<>(roles.size());
        RoleAuthority authority;
        for (Role role : roles) {
            authority = new RoleAuthority(role.getId(), role.getCode());
            authorities.add(authority);
        }
        user.setAuthorities(authorities);
        return user;
    }

    @Override
    public UserDetails register(UserDto userDto) {
        User user = new User();
        user.setUsername(userDto.getUsername());
        user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        user.setStatus(UserStatus.ACTIVE);
        try {
            if (userMapper.insert(user) <= 0) {
                throw new BusinessException("Failed to register user.");
            }
        } catch (DuplicateKeyException e) {
            throw new DuplicateException("The username '" + userDto.getUsername() + "' is already taken.");
        }

        DefaultRole defaultRole = defaultRoleMapper.selectById(1L);
        if (Objects.isNull(defaultRole)) {
            throw new BusinessException("Failed to retrieve default role configuration during registration.");
        }

        Role role = roleMapper.selectById(defaultRole.getRoleId());
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(role.getId());
        if (userRoleMapper.insert(userRole) <= 0) {
            throw new RuntimeException("Failed to assign default role to user.");
        }
        RoleAuthority authority = new RoleAuthority(role.getId(), role.getCode());
        user.setAuthorities(Set.of(authority));

        return user;
    }

    @Override
    public boolean resetPassword(ResetPasswordDto resetPasswordDto) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Unimplemented method 'resetPassword'");
    }

}
Please optimize the code