package sklep.controller;

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

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import sklep.model.Product;
import sklep.repository.ProductRepository;
import sklep.utils.ExceptionUtils;

@Controller
public class ProductController {
	@Autowired
	private ProductRepository productRepository;
	
	@GetMapping("/products")
	public String readAllProducts(Model model) {
		List<Product> products = productRepository.findAll(Sort.by("productId"));
		model.addAttribute("products", products);
		
		return "products";
	}
	
	@GetMapping("/products/{id}")
	public String readOneProduct(Model model, @PathVariable("id") int productId) {
		Optional<Product> product = productRepository.findById(productId);
		if(product.isPresent()) {
			model.addAttribute("product", product.get());
			return "product";
		} else {
			model.addAttribute("product_id", productId);
			return "missing_product";			
		}
	}
	
	@GetMapping("/products/new")
	public String newProduct(Product product) {
		return "product_form";
	}
	
	@GetMapping("/products/{id}/edit")
	public String editProduct(Model model, @PathVariable("id") int productId) {
		Optional<Product> product = productRepository.findById(productId);
		if(product.isPresent()) {
			model.addAttribute("product", product.get());
			return "product_form";
		} else {
			model.addAttribute("product_id", productId);
			return "missing_product";			
		}
	}
	
	@PostMapping({"/products/new", "/products/{id}/edit"})
	public String saveProduct(
			@Valid Product product,
			BindingResult bindingResult,
			Model model) {
		// W tej wersji dane z wypełnionego formularza odbieramy w postaci jednego obiektu Product.
		// Spring sam wpisze dane do pól o takich samych nazwach.
		// Taki parametr od razu staje się częścią modelu (to jest tzw. ModelAttribute)
		// i nie trzeba dodawać go w osobnym poleceniu.
		
		// Kwestia Bean Validation:
		// W tej wersji przed parametrem Product jest adnotacja @Valid
		// i dodatkowo do metoda posiada parametr BindingResult.
		// Wówczas Spring dokonuje walidacji obiektu przed wywołaniem tej metody
		// i informacje o wyniku walidacji przekazuje w parametrze BindingResult.
		// Metoda jest wywoływana zawsze, a to programista ma sprawdzić czy walidacja się powiodła.
		// W BindingResult znajdują się też informacje o błędach.
		// Gdybyśmy mimo błędów spróbowali wywołać save, to wtedy Hibernate zablokuje taki zapis.
		
		// W tej wersji po poprawnym zapisie przechodzimy na stronę ze szczegółami produktu.
		if(bindingResult.hasErrors()) {
			// błędów już nie dodajemy oddzielne, bo będą wyświeltlone przez f:error
			// model.addAttribute("errors", bindingResult.getAllErrors());
			return "product_form";
		} else try {
			System.out.println("Produkt przed zapisem: " + product);
			productRepository.save(product);
			System.out.println("Produkt po zapisie   : " + product);
			return "redirect:/products/" + product.getProductId();
		} catch(Exception e) {
			System.out.println("Produkt bez zapisu   : " + product);
			model.addAttribute("errors", ExceptionUtils.allMessages(e));
			return "product_form";
		}
	}

}
