package nl.kreditor.api.controller;

import nl.kreditor.model.ERole;
import nl.kreditor.model.Role;
import nl.kreditor.model.User;
import nl.kreditor.payload.request.LoginRequest;
import nl.kreditor.payload.request.SignupRequest;
import nl.kreditor.payload.response.JwtResponse;
import nl.kreditor.payload.response.MessageResponse;
import nl.kreditor.repository.RoleRepository;
import nl.kreditor.repository.UserRepository;
import nl.kreditor.security.jwt.JwtUtils;
import nl.kreditor.security.services.KreditorUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    UserRepository userRepository;

    @Autowired
    RoleRepository roleRepository;

    @Autowired
    PasswordEncoder encoder;

    @Autowired
    JwtUtils jwtUtils;

    /**
     * Validate if current session is still valid. Returns HTTP 204 No Content when successful.
     */
    @GetMapping("/ping")
    @io.swagger.v3.oas.annotations.Operation(tags = {"app"})
    @PreAuthorize("hasRole('USER')")
    public ResponseEntity<?> ping() {
        return ResponseEntity.noContent().build();
    }

    @PostMapping("/signin")
    @io.swagger.v3.oas.annotations.Operation(tags = {"app"})
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));

        SecurityContextHolder.getContext().setAuthentication(authentication);
        String jwt = jwtUtils.generateJwtToken(authentication);

        KreditorUserDetails userDetails = (KreditorUserDetails) authentication.getPrincipal();
        List<String> roles = userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());

        System.out.println(userDetails);

        return ResponseEntity.ok(new JwtResponse(jwt,
                userDetails.getId(),
                userDetails.getUsername(),
                roles));
    }

    @PostMapping("/signup")
    @io.swagger.v3.oas.annotations.Operation(tags = {"app"})
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) {
        if (userRepository.existsByUsername(signUpRequest.getUsername())) {
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Username is already taken!"));
        }

        // Create new user's account
        User user = new User(signUpRequest.getName(),
                signUpRequest.getUsername(),
                encoder.encode(signUpRequest.getPassword()));

        Set<Role> roles = new HashSet<>();

        Role userRole = roleRepository
                .findByName(ERole.ROLE_USER)
                .orElseThrow(() -> new RuntimeException("Error: Role '" + ERole.ROLE_USER + "' is not found."));

        roles.add(userRole);
        user.setRoles(roles);

        userRepository.save(user);

        return ResponseEntity.ok(new MessageResponse("User registered successfully!"));
    }
}

@@ -1383,16 +1383,19 @@
 g(%22/api/
+v1/
 auth%22)%0Ap

Fix incorrect API URL mapping for AuthController