ItemController.java

package com.student_loan.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;

import com.student_loan.dtos.ItemRecord;
import com.student_loan.model.Item;
import com.student_loan.model.User;
import com.student_loan.service.ItemService;
import com.student_loan.service.LoanService;
import com.student_loan.service.UserService;
import com.student_loan.utils.ImageUtil;

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

/**
 * Controller class for managing items in the system. Handles HTTP requests
 * related to item operations such as creating, updating, deleting, and
 * retrieving items.
 */
@RestController
@RequestMapping("/items")
public class ItemController {
	
    private static final Logger logger = LoggerFactory.getLogger(ItemController.class);

    @Autowired
    private ItemService itemService;
    @Autowired
    private UserService userService;
	@Autowired
    private LoanService loanService;

	/**
	 * Constructor for ItemController.
	 *
	 * @param itemService Service for item operations.
	 * @param userService Service for user operations.
	 * @param loanService Service for loan operations.
	 */
	@Autowired
	public ItemController(ItemService itemService, UserService userService, LoanService loanService) {
		this.itemService = itemService;
		this.userService = userService;
		this.loanService = loanService;
	}

	/**
	 * Retrieves the authenticated user from the SecurityContext.
	 *
	 * @return The authenticated user.
	 */
	private User getAuthenticatedUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String email = authentication.getName();
        return userService.getUserByEmail(email);
    }

	/**
	 * Retrieves all items in the system.
	 *
	 * @return List of all items.
	 */
    @GetMapping
    public ResponseEntity<List<Item>> getAllItems() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		String email = authentication.getName();

    	User user = userService.getUserByEmail(email);
        if (user == null) { // || user.getAdmin()==false) {  Temporal
			return new ResponseEntity<>(new ArrayList<>(),HttpStatus.UNAUTHORIZED);
        }
    	
    	return new ResponseEntity<>(itemService.getAllItems(),HttpStatus.OK);
    }

    /**
     * Retrieves all available items in the system.
     *
     * @return ResponseEntity containing a list of available items.
     * 
     *

     */
    
    @GetMapping("/available")
    public ResponseEntity<List<Item>> getAvailableItems() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		String email = authentication.getName();

    	User user = userService.getUserByEmail(email);
        if (user == null) {
			return new ResponseEntity<>(new ArrayList<>(),HttpStatus.UNAUTHORIZED);
        }
    	
    	return new ResponseEntity<>(itemService.getAvailableItems(),HttpStatus.OK);
    }

	
	 /**
     * Retrieves all items owned by a specific user.
     *
     * @param id The ID of the user.
     * @return ResponseEntity containing a list of items owned by the user.
     */
    @GetMapping("/user/{id}")
    public ResponseEntity<List<Item>> getItemsByUser(@PathVariable Long id) {
    	Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		String email = authentication.getName();

    	User user = userService.getUserByEmail(email);
		
        if (user == null) { // || (user.getAdmin()==false && user.getId()!=id)) { TODO Uncomment to enable a user only to see its own items
			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }else {
        	try {
    			List<Item> items = itemService.getItemsByUser(id);
    			return new ResponseEntity<>(items, HttpStatus.OK);
			} catch (RuntimeException e) {
				return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
			}
        }
    }
    
	/**
	 * Retrieves all available items in the system using a token for authentication.
	 *
	 * @param token The authentication token.
	 * @return ResponseEntity containing a list of available items.
	 * 
	 *  @GetMapping("/available")
    public ResponseEntity<List<Item>> getAvailableItems(@RequestParam("token") String token) {
    	User user = userService.getUserByToken(token);
        if (user == null) {
        	return new ResponseEntity<>(new ArrayList<>(),HttpStatus.UNAUTHORIZED);
        }
        List<Item> items = itemService.getItemsByAvailability(Item.ItemStatus.AVAILABLE);
        return new ResponseEntity<>(items, HttpStatus.OK);
    }
	 */
   
    
	/**
	 * Retrieves an item by its ID.
	 *
	 * @param id The ID of the item.
	 * @return ResponseEntity containing the item.
	 */
    @GetMapping("/{id}")
	public ResponseEntity<Item> getItemById(@PathVariable Long id) {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		String email = authentication.getName();

		User user = userService.getUserByEmail(email);
		Optional<Item> optionalItem = itemService.getItemById(id);

		if (user == null || optionalItem.isEmpty()) {
			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); // o 404 si prefieres
		}

		Item item = optionalItem.get();

		if (!item.getOwner().equals(user.getId())) { // TODO && !user.getAdmin()) {
			return new ResponseEntity<>(HttpStatus.FORBIDDEN);
		}

		return new ResponseEntity<>(item, HttpStatus.OK);
	}
    
    /**
     * Retrieves all items lent by the authenticated user.
     *
     * @return ResponseEntity containing a list of lent items.
     */
	@GetMapping("/lent")
	public ResponseEntity<List<Item>> getLentItemsByUser() {
		// Obtener el usuario autenticado desde el SecurityContext
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		String email = authentication.getName(); // Usamos el email como identificador

		// Buscar al usuario por el email
		User user = userService.getUserByEmail(email);
		if (user == null) {
			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
		}

		try {
			// Obtener los items que el usuario ha prestado
			List<Long> lentItemsId = loanService.getLentItemsIdByUser(user.getId());
			List<Item> lentItems = itemService.getItemsById(lentItemsId);

			return new ResponseEntity<>(lentItems, HttpStatus.OK);
		} catch (RuntimeException e) {
			// Si ocurre un error, devolvemos un error 500
			return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	/**
     * Retrieves all items borrowed by the authenticated user.
     *
     * @return ResponseEntity containing a list of borrowed items.
     */
	@GetMapping("/borrowed")
	public ResponseEntity<List<Item>> getBorrowedItemsByUser() {
		// Obtener el usuario autenticado desde el SecurityContext
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		String email = authentication.getName(); // Usamos el email como identificador

		// Buscar al usuario por el email
		User user = userService.getUserByEmail(email);
		if (user == null) {
			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
		}

		try {
			// Obtener los items que el usuario ha prestado
			List<Long> lentItemsId = loanService.getBorrowedItemsIdByUser(user.getId());
			List<Item> lentItems = itemService.getItemsById(lentItemsId);

			return new ResponseEntity<>(lentItems, HttpStatus.OK);
		} catch (RuntimeException e) {
			// Si ocurre un error, devolvemos un error 500
			return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	 /**
     * Creates a new item.
     *
     * @param itemRecord The item data.
     * @return ResponseEntity indicating the result of the operation.
     */
    @PostMapping("/create")
    public ResponseEntity<String> createItem(@RequestBody ItemRecord itemRecord) {
        User user = getAuthenticatedUser();
 		if (user == null) {
 			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
 		}
 		
 		Item item = convertToItem(itemRecord);
 		item.setOwner(user.getId());
 		try {
			if (itemRecord.imageBase64() != null && !itemRecord.imageBase64().isEmpty()) {
				String imageUrl = ImageUtil.saveBase64Image(itemRecord.imageBase64(), "uploads");
				item.setImage(imageUrl); // Esto será "/images/xxxx.png"
			}
 			itemService.saveItem(item);
        } catch (IOException e) {
			// Captura la excepción y responde con error 500
			return new ResponseEntity<>("Error al guardar la imagen: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (RuntimeException e) {
             return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
         }
 		// If the item is created successfully, return a 201 Created response
 		return new ResponseEntity<>(HttpStatus.CREATED);
    }

	

    /**
     * Creates a new item using a token for authentication.
     *
     * @param itemRecord The item data.
     * @param token      The authentication token.
     * @return ResponseEntity indicating the result of the operation.
     */
	@PostMapping(params = "token")
     public ResponseEntity<String> createItem(@RequestBody ItemRecord itemRecord, @RequestParam("token") String token) {
         User user = userService.getUserByToken(token);
         if (user == null) {
             return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
         }
         Item item = convertToItem(itemRecord);
         item.setOwner(user.getId());
         try {
             itemService.saveItem(item);
         } catch (RuntimeException e) {
             return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
         }
         return new ResponseEntity<>(HttpStatus.CREATED);
     }

	
	 /**
     * Deletes an item by its ID.
     *
     * @param id    The ID of the item.
     * @param token The authentication token.
     * @return ResponseEntity indicating the result of the operation.
     */
	
    @DeleteMapping("/{id}")
    public ResponseEntity<String> deleteItem(@PathVariable Long id, @RequestParam("token") String token) {
        User user = userService.getUserByToken(token);
        if (user == null || user.getAdmin()==false && user.getId()!=itemService.getItemById(id).get().getOwner()) {
			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
		
        }
    	
    	itemService.deleteItem(id);
    	return new ResponseEntity<>(HttpStatus.OK);
    }
    
    /**
     * Updates an item by its ID.
     *
     * @param id       The ID of the item.
     * @param item     The updated item data.
     * @param token    The authentication token.
     * @return ResponseEntity indicating the result of the operation.
     */
    @PutMapping("/{id}")
	public ResponseEntity<String> updateItem(@PathVariable Long id, @RequestBody ItemRecord item, @RequestParam("token") String token) {
    	User user = userService.getUserByToken(token);
		if (user == null || user.getId()!=Long.valueOf(itemService.getItemById(id).get().getOwner()) && user.getAdmin()!=true) {
			return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
		}
		
    	try {
    		Item itemToModify = itemService.getItemById(id).get();
			itemToModify.setName(item.name() == null ? itemToModify.getName() : item.name() );
			itemToModify.setDescription(item.description() == null ? itemToModify.getDescription() : item.description() );
			itemToModify.setCategory(item.category() == null ? itemToModify.getCategory() : item.category());
			itemToModify.setImage(item.imageBase64() == null ? itemToModify.getImage() : item.imageBase64());
			itemToModify.setStatus(Item.ItemStatus.valueOf(item.status()==null ? itemToModify.getStatus().toString() : item.status()));
			itemToModify.setCondition(Item.ItemCondition.valueOf(item.condition()==null ? itemToModify.getCondition().toString() : item.condition()));
			itemService.saveItem(itemToModify);
			return new ResponseEntity<>(HttpStatus.OK);
		} catch (RuntimeException e) {
			return new ResponseEntity<>(e.getMessage(),HttpStatus.NOT_FOUND);
		}
	}

    /**
     * Converts an ItemRecord to an Item entity.
     *
     * @param itemRecord The item record.
     * @return The converted Item entity.
     */
    private Item convertToItem(ItemRecord itemRecord) {
		Item item = new Item();
		item.setName(itemRecord.name());
		item.setDescription(itemRecord.description());
		item.setCategory(itemRecord.category());
		item.setImage(itemRecord.imageBase64());
		item.setStatus(Item.ItemStatus.valueOf(itemRecord.status().toUpperCase()));
		item.setPurchaseDate(new java.util.Date());
		item.setPurchasePrice(Double.valueOf(itemRecord.purchasePrice()));
		item.setCondition(Item.ItemCondition.valueOf(itemRecord.condition().toUpperCase()));
		return item;
    }
}