LeaderboardController.java

package no.ntnu.idi.stud.savingsapp.controller.leaderboard;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import no.ntnu.idi.stud.savingsapp.dto.leaderboard.LeaderboardDTO;
import no.ntnu.idi.stud.savingsapp.dto.leaderboard.LeaderboardEntryDTO;
import no.ntnu.idi.stud.savingsapp.model.leaderboard.Leaderboard;
import no.ntnu.idi.stud.savingsapp.model.leaderboard.LeaderboardFilter;
import no.ntnu.idi.stud.savingsapp.model.leaderboard.LeaderboardType;
import no.ntnu.idi.stud.savingsapp.security.AuthIdentity;
import no.ntnu.idi.stud.savingsapp.service.LeaderboardService;
import no.ntnu.idi.stud.savingsapp.validation.Enumerator;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Controller class for handling leaderboard-related requests.
 */
@RestController
@RequestMapping("/api/leaderboard")
@EnableAutoConfiguration
@Tag(name = "Leaderboard")
@Slf4j
public class LeaderboardController {

	@Autowired
	private LeaderboardService leaderboardService;

	@Autowired
	private ModelMapper modelMapper;

	/**
	 * Retrieves the leaderboard entries based on the specified type, filter, and entry
	 * count.
	 * @param identity The authenticated user's identity.
	 * @param type The type of leaderboard.
	 * @param filter The filter for the leaderboard entries.
	 * @param entryCount The number of leaderboard entries to retrieve.
	 * @return ResponseEntity containing the leaderboard data.
	 */
	@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<LeaderboardDTO> getLeaderboard(@AuthenticationPrincipal AuthIdentity identity,
			@RequestParam @Enumerator(value = LeaderboardType.class, message = "Invalid type") String type,
			@RequestParam @Enumerator(value = LeaderboardFilter.class, message = "Invalid filter") String filter,
			@RequestParam(defaultValue = "10", required = false) int entryCount) {
		Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.valueOf(type),
				LeaderboardFilter.valueOf(filter), entryCount, identity.getId());
		LeaderboardDTO leaderboardDTO = modelMapper.map(leaderboard, LeaderboardDTO.class);
		log.info("[LeaderboardController:getLeaderboard] type: {}, filter: {}, count: {}", type, filter, entryCount);
		for (LeaderboardEntryDTO leaderboardEntryDTO : leaderboardDTO.getEntries()) {
			log.info("[LeaderboardController:getLeaderboard] entry: {}, rank: {}, score: {}",
					leaderboardEntryDTO.getUser().getId(), leaderboardEntryDTO.getRank(),
					leaderboardEntryDTO.getScore());
		}
		return ResponseEntity.ok(leaderboardDTO);
	}

	/**
	 * Retrieves the surrounding leaderboard entries for the authenticated user.
	 * @param identity The authenticated user's identity.
	 * @param type The type of leaderboard.
	 * @param filter The filter for the leaderboard entries.
	 * @param entryCount The number of leaderboard entries to retrieve.
	 * @return ResponseEntity containing the surrounding leaderboard entries.
	 */
	@GetMapping(value = "/surrounding", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<LeaderboardDTO> getSurrounding(@AuthenticationPrincipal AuthIdentity identity,
			@RequestParam @Enumerator(value = LeaderboardType.class, message = "Invalid type") String type,
			@RequestParam @Enumerator(value = LeaderboardFilter.class, message = "Invalid filter") String filter,
			@RequestParam(defaultValue = "10", required = false) int entryCount) {
		Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.valueOf(type),
				LeaderboardFilter.valueOf(filter), entryCount, identity.getId());
		LeaderboardDTO leaderboardDTO = modelMapper.map(leaderboard, LeaderboardDTO.class);
		log.info("[LeaderboardController:getLeaderboard] type: {}, filter: {}, count: {}", type, filter, entryCount);
		for (LeaderboardEntryDTO leaderboardEntryDTO : leaderboardDTO.getEntries()) {
			log.info("[LeaderboardController:getLeaderboard] entry: {}, rank: {}, score: {}",
					leaderboardEntryDTO.getUser().getId(), leaderboardEntryDTO.getRank(),
					leaderboardEntryDTO.getScore());
		}
		return ResponseEntity.ok(leaderboardDTO);
	}

	@Operation(summary = "Get sum of total points globally",
			description = "Get the sum of the total points of all users globally")
	@ApiResponses({ @ApiResponse(responseCode = "200", description = "Successfully retrieved total points") })
	@GetMapping(value = "/total-points", produces = MediaType.APPLICATION_JSON_VALUE)
	public ResponseEntity<Long> getTotalPoints() {
		long totalPoints = leaderboardService.getSumTotalEarnedPoints();
		log.info("[LeaderboardController:getTotalPoints] points: {}", totalPoints);
		return ResponseEntity.ok(totalPoints);
	}

}