ItemController.java

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

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
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.store.InventoryDTO;
import no.ntnu.idi.stud.savingsapp.dto.store.ItemDTO;
import no.ntnu.idi.stud.savingsapp.model.store.Item;
import no.ntnu.idi.stud.savingsapp.model.user.User;
import no.ntnu.idi.stud.savingsapp.security.AuthIdentity;
import no.ntnu.idi.stud.savingsapp.service.ItemService;
import no.ntnu.idi.stud.savingsapp.service.UserService;

import java.util.ArrayList;
import java.util.List;

import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * Controller handling item related requests.
 */
@CrossOrigin
@RestController
@Validated
@RequestMapping("/api/item")
@EnableAutoConfiguration
@Tag(name = "Item", description = "Endpoints for managing store and user inventory.")
@Slf4j
public class ItemController {

	@Autowired
	private ItemService itemService;

	@Autowired
	private UserService userService;

	@Autowired
	private ModelMapper modelMapper;

	@Operation(summary = "Get available store items",
			description = "Retrieves all items available in the store and a flag indicating whether the user has purchased each item.")
	@ApiResponses({ @ApiResponse(responseCode = "200", description = "List of store items fetched successfully") })
	@GetMapping("/store")
	public ResponseEntity<List<ItemDTO>> getStore(@AuthenticationPrincipal AuthIdentity identity) {
		List<Item> store = itemService.getStore();
		List<Item> inventory = itemService.getInventory(identity.getId());
		List<ItemDTO> storeDTO = new ArrayList<>();
		for (Item item : store) {
			ItemDTO itemDTO = modelMapper.map(item, ItemDTO.class);
			if (inventory.contains(item)) {
				itemDTO.setAlreadyBought(true);
			}
			log.info("[ItemController:getStore] item: {}", itemDTO.getId());
			storeDTO.add(itemDTO);
		}
		return ResponseEntity.ok(storeDTO);
	}

	@Operation(summary = "Get the active user's inventory items",
			description = "Retrieves a list of all items currently in the inventory of the active user.")
	@ApiResponses({ @ApiResponse(responseCode = "200", description = "List of inventory items fetched successfully") })
	@GetMapping("/inventory")
	public ResponseEntity<List<InventoryDTO>> getInventory(@AuthenticationPrincipal AuthIdentity identity) {
		List<Item> inventory = itemService.getInventory(identity.getId());
		List<InventoryDTO> inventoryDTO = new ArrayList<>();
		for (Item item : inventory) {
			inventoryDTO.add(modelMapper.map(item, InventoryDTO.class));
			log.info("[ItemController:getInventory] item: {}", item.getId());
		}
		return ResponseEntity.ok(inventoryDTO);
	}

	@Operation(summary = "Get user inventory items",
			description = "Retrieves a list of all items currently in the inventory of the user.")
	@ApiResponses({ @ApiResponse(responseCode = "200", description = "List of inventory items fetched successfully") })
	@GetMapping("/inventory/{userId}")
	public ResponseEntity<List<InventoryDTO>> getInventoryByUserId(@PathVariable Long userId) {
		List<Item> inventory = itemService.getInventory(userId);
		List<InventoryDTO> inventoryDTO = new ArrayList<>();
		for (Item item : inventory) {
			inventoryDTO.add(modelMapper.map(item, InventoryDTO.class));
			log.info("[ItemController:getInventoryByUserId] item: {}", item.getId());
		}
		return ResponseEntity.ok(inventoryDTO);
	}

	@Operation(summary = "Purchase an item",
			description = "Performs a purchase of the item by the user. Points will be deducted from the user.")
	@ApiResponses({
			@ApiResponse(responseCode = "201", description = "Item purchased and added to inventory successfully",
					content = @Content(mediaType = "application/json")),
			@ApiResponse(responseCode = "403", description = "Insufficient points to purchase the item",
					content = @Content(mediaType = "application/json",
							schema = @Schema(implementation = String.class))) })
	@PostMapping("/{itemId}")
	@ResponseStatus(HttpStatus.CREATED)
	public ResponseEntity<String> buyItem(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long itemId) {
		Item item = itemService.getItemFromId(itemId);
		User user = userService.findById(identity.getId());
		boolean purchaseSuccessful = itemService.addItem(user, item);

		if (purchaseSuccessful) {
			log.info("[ItemController:buyItem] item: {}, user: {}", item.getId(), user.getId());
			return ResponseEntity.status(HttpStatus.CREATED).build();
		}
		else {
			log.error("[ItemController:buyItem] Insufficient points to purchase the item");
			return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Insufficient points to purchase the item");
		}
	}

}