package org.hso.ecommerce.controller.intern;

import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.shop.Category;
import org.hso.ecommerce.entities.shop.Image;
import org.hso.ecommerce.entities.supplier.ArticleOffer;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CategoryRepository;
import org.hso.ecommerce.repos.shop.ImageRepository;
import org.hso.ecommerce.repos.shop.OffersRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.view.RedirectView;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Controller
@RequestMapping("intern/articles")
public class InternArticleController {
	@Autowired
	private final ArticleRepository articleRepository = null;

	@Autowired
	private final WarehouseBookingPositionSlotEntryRepository warehouseEntryRepository = null;

	@Autowired
	private final CategoryRepository categoryRepository = null;

	@Autowired
	private final OffersRepository offersRepository = null;

	@Autowired
	private final ImageRepository imageRepository = null;

	@GetMapping("/")
	public String internListedArticles(Model model) {

		List<UImodelArticles> totals = new ArrayList<UImodelArticles>();

		for (Article article : articleRepository.findAll()) {
			UImodelArticles tmp = new UImodelArticles();
			tmp.addListedArticle(article, warehouseEntryRepository.getArticleStock(article.id).orElse(0));
			totals.add(tmp);
		}

		model.addAttribute("ListedArticles", totals);
		return "intern/listedArticles/index";
	}

	@GetMapping("/{id}")
	public String internListedArticlesId(Model model, @PathVariable String id) {
		int articleid = Integer.parseInt(id);
		UImodelArticle total = new UImodelArticle();
		total.addArticle(articleRepository.findArticleById(articleid),
				warehouseEntryRepository.getArticleStock(articleid).orElse(0));

		model.addAttribute("ArticleID", total);
		return "intern/listedArticles/id";
	}

	@PostMapping("/{id}/saveChanges")
	public RedirectView saveChanges(@PathVariable(required = true) int id,
			@RequestParam(value = "title", required = true) String title,
			@RequestParam(value = "description", required = true) String description,
			@RequestParam(value = "units-per-slot", required = true) String warehouseUnitsPerSlot,
			@RequestParam(value = "priceNet", required = true) String pricenetto,
			@RequestParam(value = "reorderMaxPrice", required = true) String reorderMaxPrice,
			@RequestParam(value = "autobuy", required = true) Boolean shouldReorder,
			@RequestParam(value = "categorie", required = true) String categories,
			@RequestParam(value = "img", required = true) MultipartFile imgFile) {

		Article tmpArticle = articleRepository.findArticleById(id); // get the old article

		String[] separatedCategories = categories.split("\n");

		tmpArticle.categories.clear();

		// loop through all categories strings and create a new category if a new one;
		// also adds the categories to the article
		for (String category : separatedCategories) {
			tmpArticle.categories.add(categoryRepository.findCategoryByName(category.trim())
					.orElseGet(() -> new Category(category.trim())));
		}

		tmpArticle.shouldReorder = shouldReorder;
		tmpArticle.reorderMaxPrice = (int) (Float.parseFloat(reorderMaxPrice) * 100);
		tmpArticle.shopPricePerUnitNetCent = (int) (Float.parseFloat(pricenetto) * 100);
		tmpArticle.warehouseUnitsPerSlot = Integer.parseInt(warehouseUnitsPerSlot);
		tmpArticle.title = title;
		updateImage(tmpArticle, imgFile);
		tmpArticle.description = description;

		articleRepository.save(tmpArticle); // save updated article
		return new RedirectView("../"); // return to overview page

	}

	@PostMapping("/addArticle/{id}")
	public RedirectView addArticle(@PathVariable(required = true) String id) {
		// article is not already listed, create new one
		int offeredArticleID = Integer.parseInt(id);

		Article tmpArticle = new Article();

		ArticleOffer offeredArticle = offersRepository.findOfferedArticleById(offeredArticleID);

		// set default values
		tmpArticle.description = "";
		tmpArticle.reorderMaxPrice = 0;
		tmpArticle.shopPricePerUnitNetCent = offeredArticle.pricePerUnitNet;
		tmpArticle.shouldReorder = false;
		tmpArticle.title = offeredArticle.title;
		tmpArticle.warehouseUnitsPerSlot = 1;
		setDefaultImage(tmpArticle);
		tmpArticle.related = offeredArticle;
		articleRepository.save(tmpArticle); // save new article

		// return to edit article page
		return new RedirectView("../" + articleRepository.findArticleIDByRelatedID(offeredArticleID).get());
	}

	private void setDefaultImage(Article article) {
		String defaultImagePath = "./data/img/no_product_img.jpg"; // path + name of default img
		Optional<Integer> imageID = imageRepository.findImageIDByPath(defaultImagePath); // get default img

		if (imageID.isPresent()) {
			// default img is in DB
			article.image = imageRepository.findImageById(imageID.get()); // set default img to new article
		} else {
			// default img is not in DB
			File tmpFile = new File(defaultImagePath);
			// test if default img file exits
			if (!tmpFile.exists()) {
				// fallback if the file not exists
				// create new file
				BufferedImage bufferedImage = new BufferedImage(422, 428, BufferedImage.TYPE_INT_RGB);
				try {
					ImageIO.write(bufferedImage, "jpg", new File(defaultImagePath)); // save new file on disk
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			Image defaultImage = new Image();
			defaultImage.path = defaultImagePath; // set new file to default img
			imageRepository.save(defaultImage); // save default img
			article.image = defaultImage; // set default img to new article
		}
	}

	private void updateImage(Article article, MultipartFile imgFile) {
		// check if a file is present
		if (imgFile.getSize() > 0) {
			try {
				// get file name based on MD5 hash
				String fileName = DigestUtils.md5DigestAsHex(imgFile.getBytes()) + ".jpg";
				// check if img is already in system
				Optional<Integer> imageID = imageRepository.findImageIDByPath("./data/img/" + fileName);
				if (imageID.isPresent()) {
					article.image = imageRepository.findImageById(imageID.get()); // add existing img to article
				} else {
					// write new img file to disk
					Files.newOutputStream(Paths.get("./data/img/", fileName)).write(imgFile.getBytes());
					// create new img
					Image newImage = new Image();
					newImage.path = "./data/img/" + fileName; // set new file to new img
					imageRepository.save(newImage); // save new img
					article.image = newImage; // set new img to article
				}
			} catch (Exception e) {
				setDefaultImage(article); // if upload failed, reset to default img
			}
		}
	}

	public static class UImodelArticles {

		public String imgPath;
		public String title;
		public String price;
		public String priceNet;
		public String categorie;
		public int stock;
		public long offerID;
		public long id;

		void addListedArticle(Article article, int stock) {

			if (article.image != null) {
				this.imgPath = article.image.path;
			}
			this.title = article.title;
			this.priceNet = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
			this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));

			StringBuilder result = new StringBuilder();

			for (Category temp : article.categories) {
				result.append(temp.name + " ");
			}
			this.categorie = result.toString();

			this.stock = stock;
			this.offerID = article.related.id;
			this.id = article.id;
		}
	}

	public static class UImodelArticle {

		public String imgPath;
		public String title;
		public String price;
		public String priceNet;
		public String reorderMaxPrice;
		public String categorie;
		public int stock;
		public long offerID;
		public long id;
		public boolean shouldReorder;
		public String warehouseUnitsPerSlot;
		public String description;
		public int vatPercent;

		public String getCategorie() {
			return categorie;
		}

		public String getDescription() {
			return description;
		}

		void addArticle(Article article, int stock) {
			if (article.image != null) {
				this.imgPath = article.image.path;
			}
			this.title = article.title;
			this.priceNet = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
			this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));

			StringBuilder result = new StringBuilder();

			for (Category temp : article.categories) {
				result.append(temp.name);
				result.append("\n");
			}
			this.categorie = result.toString();

			this.stock = stock;
			this.offerID = article.related.id;
			this.id = article.id;
			this.reorderMaxPrice = String.format("%.2f", ((float) article.reorderMaxPrice / 100));
			this.shouldReorder = article.shouldReorder;
			this.warehouseUnitsPerSlot = String.valueOf(article.warehouseUnitsPerSlot);
			this.description = article.description;
			this.vatPercent = article.related.vatPercent;
		}
	}

}
