package org.hso.ecommerce.controller.intern.warehouse;

import org.hso.ecommerce.action.warehouse.CreateManuelBookingAction;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.warehouse.Slot;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.warehouse.SlotRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;

@Controller
@RequestMapping("/intern/warehouse/")
public class ManuelBookingController {

    @Autowired
    private final ArticleRepository articleRepository = null;

    @Autowired
    private final SlotRepository slotRepository = null;

    @Autowired
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;

    @Autowired
    private final WarehouseBookingRepository warehouseBookingRepository = null;

    @GetMapping("addManual")
    public String warehouseAddManual(
            Model model
    ) {

        model.addAttribute("articles", articleRepository.findAll());
        model.addAttribute("slots", slotRepository.findAll());

        return "intern/warehouse/addManual";
    }

    @PostMapping("addManual")
    public String warehouseAddMaualPost(
            Model model,
            HttpServletRequest request,
            HttpServletResponse response,
            @RequestParam("articleId") String articleIdText,
            @RequestParam("amount") Integer amount,
            @RequestParam("reason") String reason,
            @RequestParam("sourceIsSlot") Boolean sourceIsSlot,
            @RequestParam("sourceSlot") Integer sourceSlotNum,
            @RequestParam("destinationIsSlot") Boolean destinationIsSlot,
            @RequestParam("destinationSlot") Integer destinationSlotNum
    ) {

        // The suggestions for articleId in the UI show articles names, seperated by a " - ".
        // The Number must be extracted first.
        long articleId = -1;
        try {
            articleId = Long.parseLong(articleIdText.split(" - ", 2)[0].trim());
        } catch (NumberFormatException e) {
            model.addAttribute("error", "Die Artikel Id konnte nicht erkannt werden.");
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return "intern/warehouse/addManual";
        }


        Optional<Article> optionalArticle = articleRepository.findById(articleId);
        Article article = null;
        if (!optionalArticle.isPresent()) {
            model.addAttribute("error", "Der Artikel konnte nicht gefunden werden.");
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
            return "intern/warehouse/addManual";
        } else {
            article = optionalArticle.get();
        }

        if (amount <= 0) {
            model.addAttribute("error", "Eine  Anzahl <= 0 kann nicht verbucht werden.");
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
            return "intern/warehouse/addManual";
        }

        if (sourceIsSlot == false && destinationIsSlot == false) {
            model.addAttribute("error", "Jede Buchung benötigt ein Ziel oder eine Quelle.");
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
            return "intern/warehouse/addManual";
        }

        Optional<WarehouseBookingPositionSlotEntry> sourceSlot = Optional.empty();
        if (sourceIsSlot == true) {
            sourceSlot = warehouseBookingPositionSlotEntryRepository.getBySlotNum(sourceSlotNum);
            if (!sourceSlot.isPresent()) {
                request.setAttribute("error", "Quelllagerplatz wurde nicht gefunden oder ist leer.");
                response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
                return "intern/warehouse/addManual";
            }
        }

        Optional<WarehouseBookingPositionSlotEntry> destinationSlot = Optional.empty();
        if (destinationIsSlot == true) {
            Optional<Slot> slot = slotRepository.findBySlotNum(destinationSlotNum);
            if (!slot.isPresent()) {
                request.setAttribute("error", "Ziellagerplatz wurde nicht gefunden.");
                response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
                return "intern/warehouse/addManual";
            }

            Article finalArticle = article;
            destinationSlot = Optional.of(warehouseBookingPositionSlotEntryRepository.getBySlotNum(destinationSlotNum).orElseGet(
                    () -> WarehouseBookingPositionSlotEntry.empty(finalArticle, slot.get())
            ));
        }

        try {
            warehouseBookingRepository.save(
                    new CreateManuelBookingAction(article, amount, sourceSlot, destinationSlot, reason).finish()
            );
        } catch (CreateManuelBookingAction.ArticleSlotConstraintArticleTypeFailedException e) {
            model.addAttribute("error", "Es befindet sich der falsche Artikeltyp in Quell- oder Ziellagerplatz. ");
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
            return "intern/warehouse/addManual";
        } catch (CreateManuelBookingAction.ArticleSlotConstraintFailedException e) {
            model.addAttribute("error", "Die maximale Anzahl an lagerbaren Artikeln im Ziellagerplatz wurde überschritten.");
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
            return "intern/warehouse/addManual";
        }

        return "redirect:/intern/warehouse/todo";
    }

}
