content: package com.clone.instagram.authservice.endpoint;
  
  import com.clone.instagram.authservice.exception.*;
  import com.clone.instagram.authservice.model.InstaUserDetails;
  import com.clone.instagram.authservice.model.Profile;
  import com.clone.instagram.authservice.model.User;
  import com.clone.instagram.authservice.payload.*;
  import com.clone.instagram.authservice.service.JwtTokenProvider;
  import com.clone.instagram.authservice.service.UserService;
  import lombok.extern.slf4j.Slf4j;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.http.HttpStatus;
  import org.springframework.http.MediaType;
  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.annotation.AuthenticationPrincipal;
  import org.springframework.security.core.context.SecurityContextHolder;
  import org.springframework.web.bind.annotation.*;
  import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
  
  import javax.validation.Valid;
  import java.net.URI;
  import java.util.List;
  import java.util.stream.Collectors;
  
  @RestController
  @Slf4j
  public class UserEndpoint {
  
      @Autowired
      private UserService userService;
  
      @Autowired
      private AuthenticationManager authenticationManager;
  
      @Autowired
      private JwtTokenProvider tokenProvider;
  
  
      @PostMapping("/signin")
      public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
  
          Authentication authentication = authenticationManager.authenticate(
                  new UsernamePasswordAuthenticationToken(
                          loginRequest.getUsername(),
                          loginRequest.getPassword()
                  )
          );
  
          SecurityContextHolder.getContext().setAuthentication(authentication);
  
          String jwt = tokenProvider.generateToken(authentication);
          return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
      }
  
      @PostMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
      public ResponseEntity<?> createUser(@Valid @RequestBody SignUpRequest payload) {
          log.info("creating user {}", payload.getUsername());
  
          User user = User
                  .builder()
                  .username(payload.getUsername())
                  .email(payload.getEmail())
                  .password(payload.getPassword())
                  .userProfile(Profile
                          .builder()
                          .displayName(payload.getName())
                          .build())
                  .build();
  
          try {
              userService.registerUser(user);
          } catch (UsernameAlreadyExistsException | EmailAlreadyExistsException e) {
              throw new BadRequestException(e.getMessage());
          }
  
          URI location = ServletUriComponentsBuilder
                  .fromCurrentContextPath().path("/users/{username}")
                  .buildAndExpand(user.getUsername()).toUri();
  
          return ResponseEntity
                  .created(location)
                  .body(new ApiResponse(true,"User registered successfully"));
      }
  
      @PutMapping("/users/me/picture")
      @PreAuthorize("hasRole('USER')")
      public ResponseEntity <?> updateProfilePicture(
              @RequestBody String profilePicture,
              @AuthenticationPrincipal InstaUserDetails userDetails) {
  
          userService.updateProfilePicture(profilePicture, userDetails.getId());
  
          return ResponseEntity
                  .ok()
                  .body(new ApiResponse(true,"Profile picture updated successfully"));
      }
  
      @GetMapping(value = "/users/{username}", produces = MediaType.APPLICATION_JSON_VALUE)
      public ResponseEntity<?> findUser(@PathVariable("username") String username) {
          log.info("retrieving user {}", username);
  
          return  userService
                  .findByUsername(username)
                  .map(user -> ResponseEntity.ok(user))
                  .orElseThrow(() -> new ResourceNotFoundException(username));
      }
  
      @GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
      public ResponseEntity<?> findAll() {
          log.info("retrieving all users");
  
          return ResponseEntity
                  .ok(userService.findAll());
      }
  
      @GetMapping(value = "/users/me", produces = MediaType.APPLICATION_JSON_VALUE)
      @PreAuthorize("hasRole('USER')")
      @ResponseStatus(HttpStatus.OK)
      public UserSummary getCurrentUser(@AuthenticationPrincipal InstaUserDetails userDetails) {
          return UserSummary
                  .builder()
                  .id(userDetails.getId())
                  .username(userDetails.getUsername())
                  .name(userDetails.getUserProfile().getDisplayName())
                  .profilePicture(userDetails.getUserProfile().getProfilePictureUrl())
                  .build();
      }
  
      @GetMapping(value = "/users/summary/{username}", produces = MediaType.APPLICATION_JSON_VALUE)
      public ResponseEntity<?> getUserSummary(@PathVariable("username") String username) {
          log.info("retrieving user {}", username);
  
          return  userService
                  .findByUsername(username)
                  .map(user -> ResponseEntity.ok(convertTo(user)))
                  .orElseThrow(() -> new ResourceNotFoundException(username));
      }
  
      @PostMapping(value = "/users/summary/in", produces = MediaType.APPLICATION_JSON_VALUE)
      public ResponseEntity<?> getUserSummaries(@RequestBody List<String> usernames) {
          log.info("retrieving summaries for {} usernames", usernames.size());
  
          List<UserSummary> summaries =
                  userService
                          .findByUsernameIn(usernames)
                          .stream()
                          .map(user -> convertTo(user))
                          .collect(Collectors.toList());
  
          return ResponseEntity.ok(summaries);
  
      }
  
      private UserSummary convertTo(User user) {
          return UserSummary
                  .builder()
                  .id(user.getId())
                  .username(user.getUsername())
                  .name(user.getUserProfile().getDisplayName())
                  .profilePicture(user.getUserProfile().getProfilePictureUrl())
                  .build();
      }
  }