package sklep.rest;

import java.math.BigDecimal;
import java.util.List;

import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import sklep.db.DBConnection;
import sklep.db.DBException;
import sklep.db.ProductDAO;
import sklep.db.RecordNotFound;
import sklep.model.Product;
import sklep.photo.PhotoUtil;

/* W usługach REST struktura adresów URL odpowiada logicznej strukturze danych.
 * Typowe jest, że * pod adresem "katalogu", np. /products , dostępna jest lista wszystkich rekordów
 * (lub ogólne informacje, lub jakiś sposób przeglądania - gdyby było ich za dużo do zwrócenia na raz)
 * a idąc dalej wgłąb ścieżki przechodzimy do "pojedynczych rekordów", np. /products/2
 * 
 * W tej klasie wejdziemynawet do wnętrza produktów i udostępnimy osobno cenę
 * /products/2/price
 * W praktyce nie robi się tego zbyt często, ale tu zobaczymy jako przykład możliwości.
 * 
 * To od programisty (twórcy usługi) zależy jakie adresy i jakie operacje pod tymi adresami udostępnia.
 */

@Path("/products")
public class RProducts {

	@GET
	@Produces("application/json")
	public List<Product> wszystkieProdukty() throws DBException {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			return productDAO.readAll();
		}
	}
	
	@GET
	@Path("/{id}")
	@Produces("application/json")
	public Product produktWgId(@PathParam("id") int productId) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			return productDAO.findById(productId);
		}
	}
	
	@GET
	@Path("/{id}/price")
	@Produces("application/json")
	public BigDecimal getPrice(@PathParam("id") int productId) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			return productDAO.findById(productId).getPrice();
		}
	}
	
	// W zapytaniach typu PUT i POST klient wysyła dane na serwer (treść zapytania: "body" / "entity" / "content" ...)
	// W JAX-RS metoda może posiadać tylko jeden parametr bez adnotacji i to właśnie przez ten parametr przekazywana jest treść zapytania
	// (te dane, które przysłał klient). Format tych danych opisuje adnotacja @Consumes
	@PUT
	@Path("/{id}/price")
	@Consumes("application/json")
	public void setPrice(@PathParam("id") int productId, BigDecimal newPrice) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			Product product = productDAO.findById(productId);
			product.setPrice(newPrice);
			productDAO.save(product);
			db.commit();
		}
	}
	
	// W praktyce REST metoda POST jest używana do dodawania nowych rekordów do katalogu.
	// Może być także używana w innych celach - gdy klient ma "przysłać dane na serwer", a serwer coś z tym zrobi (podobnie jak to było w SOAP).
	
	@POST
	@Consumes("application/json")
	@Produces("application/json")
	public Product zapiszProdukt(Product product) throws DBException {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			productDAO.save(product);
			db.commit();
			return product;
		}
	}
	
	// PUT vs POST
    // PUT powinniśmy używać wtedy, gdy z góry wiadomo, pod jakim adresem zostaną zapisane dane.
    // W praktyce PUT używa się najczęściej do aktualizacji istniejących danych, ale teoretycznie PUT
    // można też użyć do zapisania nowych danych pod konkretnym adresem.
    // Gdy wyślemy dane za pomocą PUT pod adres, to następnie GET z tego samego adresu powinien odczytać dane, które wysłał PUT (być może w innym formacie).
    
    // POST używajmy wtedy, gdy nie wiemy z góry pod jakim adresem dane zostaną zapisane, np. gdy id rekordu jest generowane z sekwencji.
    // Taka metoda powinna dać w odpowiedzi informację o ID utworzonego rekordu.
    // Kilka możliwości:
    // 1) (w tej klasie) - odesłanie uzupełnionego rekordu - trochę niewydajne, ale wygodne
    // 2) minimalny dokumencik JSON, w którego wnętrzu jest zawarta ta informacja (tak robi wiele usług w praktyce, np. PayU)
    // 3) (zobaczymy jeszcze) - odesłać odpowiedź typu Created z nagłówkiem Location - najlepsze z punktu widzenia standardów/dobrych praktyk

	@DELETE
	@Path("/{id}")
	public void usun(@PathParam("id") int productId) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			productDAO.delete(productId);
			db.commit();
		}
	}
	
	@GET
	@Path("/{id}/photo")
	@Produces("image/jpeg")
	public byte[] foto(@PathParam("id") int productId) throws DBException, RecordNotFound {
		return PhotoUtil.readBytes(productId);
	}
	
}

