package sklep.rest;

import java.math.BigDecimal;
import java.net.URI;
import java.util.List;
import java.util.stream.Collectors;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import sklep.db.DBConnection;
import sklep.db.DBException;
import sklep.db.ProductDAO;
import sklep.db.RecordNotFound;
import sklep.model.Product;

@Path("/products")
@Produces({"application/xml", "application/json;charset=utf-8", "text/plain;charset=utf-8"})
@Consumes({"application/xml", "application/json"})
public class RProducts {
	
	@GET
	public List<Product> readAll() throws DBException {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			return productDAO.readAll();
		}
	}
	
	@GET
	@Produces("text/html;charset=utf-8")
	public String readAllHtml() throws DBException {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			List<Product> products = productDAO.readAll();
			
			return products.stream()
					.map(Product::getHtml)
					.collect(Collectors.joining("", "<html><body>", "</body></html>"));
		}
	}
	
	@Path("/{id}")
	@GET
	public Product readOne(@PathParam("id") int productId) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			return productDAO.findById(productId);
		}
	}
	
	@Path("/{id}")
	@GET
	@Produces("text/html;charset=utf-8")
	public String readOneHtml(@PathParam("id") int productId) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			Product product = productDAO.findById(productId);
			return "<html><body>" + product.getHtml() + "</body></html>";
		}
	}
	
	@Path("/{id}/description")
	@GET
	@Produces({"text/plain", "application/json"})
	public String getDescr(@PathParam("id") int productId) throws DBException, RecordNotFound {
		return readOne(productId).getDescription();
	}
	
	@Path("/{id}/price")
	@GET
	@Produces({"text/plain", "application/json"})
	public BigDecimal getPrice(@PathParam("id") int productId) throws DBException, RecordNotFound {
		return readOne(productId).getPrice();
	}
	
	// metoda pozwalająca zmienić cenę
	@Path("/{id}/price")
	@PUT
	@Consumes({"text/plain", "application/json"})
	public void setPrice(@PathParam("id") int productId,
			BigDecimal nowaCena) throws DBException, RecordNotFound {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			Product product = productDAO.findById(productId);
			product.setPrice(nowaCena);
			productDAO.update(product);
			db.commit();
		}
	}
	
	// W REST obowiązuje taka konwencja, że
	// 1) istniejące dane nadpisuje się metodą PUT i wtedy w adresie podaje się adres tego zasobu, który aktualizujemy
	@Path("/{id}")
	@PUT
	public void update(@PathParam("id") int productId,
			Product product) throws DBException, RecordNotFound {
		// Aby uniknąć niejednoznaczności, ustawiam w obiekcie product takie ID
		// jakie wynika ze ścieżki
		product.setProductId(productId);
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			productDAO.save(product);
			db.commit();
		}
	}
	
	// 2) gdy rekord z danymi wyśle się metodą POST pod adres
	// całej kolekcji, czyli np. /products , to oznacza to dodanie nowego rekordu do tej kolekcji
	// z automatycznie nadanym nowym ID
	@POST
	public Response insert(Product product,
			@Context UriInfo uriInfo) throws DBException, RecordNotFound {
		// Aby uniknąć niejednoznaczności, kasuję ID, nawet jeśli jest podane w produkcie
		// i zawsze zapisuję pod nowym adresem.
		product.setProductId(null);
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			productDAO.insertNew(product);
			db.commit();
			
			URI location = uriInfo.getRequestUriBuilder().path("/{id}").build(product.getProductId());
			return Response.created(location).build();
		}
	}
	
	@DELETE
	@Path("/{id}")
	public void delete(@PathParam("id") int productId) throws DBException {
		try(DBConnection db = DBConnection.open()) {
			ProductDAO productDAO = db.productDAO();
			productDAO.delete(productId);
			db.commit();
		}
	}

}
