package org.hso.ecommerce.controller.shop;

import org.hso.ecommerce.action.shop.CreateOrderAction;
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
import org.hso.ecommerce.entities.booking.PaymentMethod;
import org.hso.ecommerce.entities.shop.Address;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.shop.ShoppingCart;
import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
import org.hso.ecommerce.repos.booking.BookingRepository;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
import org.hso.ecommerce.repos.user.UserRepository;
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.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.TreeMap;

@Controller
@RequestMapping("/shop/")
public class ShopCheckoutController {

    @Autowired
    private final UserRepository userRepository = null;

    @Autowired
    private final ArticleRepository articleRepository = null;

    @Autowired
    private final BookingAccountEntryRepository bookingEntryRepository = null;

    @Autowired
    private final BookingRepository bookingRepository = null;

    @Autowired
    private final WarehouseBookingRepository warehouseBookingRepository = null;

    @Autowired
    private final CustomerOrderRepository customerOderRepository = null;

    @Autowired
    private final WarehouseBookingPositionSlotEntryRepository wbeseRepo = null;

    @GetMapping("/checkout")
    public String shopCheckout(HttpSession session,
                               HttpServletRequest request,
                               @RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart) {
        session.setAttribute("afterLogin", request.getRequestURI());

        CheckoutListTotals totals = new CheckoutListTotals();
        ArrayList<CheckoutListItem> items = new ArrayList<>();
        for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
            Article article = articleRepository.findById(item.getArticleId()).get();

            totals.addItem(article, item.getAmount());
            items.add(new CheckoutListItem(item.getAmount(), article));
        }

        request.setAttribute("checkoutItems", items);
        request.setAttribute("checkoutTotals", totals);

        return "shop/checkout";
    }

    public static class CheckoutListTotals {
        public int net;
        public TreeMap<Integer, Integer> vatAmounts = new TreeMap<>();
        public int total;

        void addItem(Article article, int amount) {
            net += article.shopPricePerUnitNetCent * amount;
            Integer vatPos = vatAmounts.getOrDefault(article.related.vatPercent, 0) + article.getVat() * amount;
            vatAmounts.put(article.related.vatPercent, vatPos);
            total += article.getPriceGross() * amount;
        }
    }

    public static class CheckoutListItem {
        public int amount;
        public Article article;
        public int total;

        public CheckoutListItem(int amount, Article article) {
            this.amount = amount;
            this.article = article;
            this.total = amount * article.getPriceGross();
        }
    }

    @PostMapping("/checkoutFinish")
    public String shopCheckoutFinish(
            HttpSession session,
            HttpServletRequest request,
            HttpServletResponse response,
            @RequestAttribute(value = "user") User user,
            @RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
            @RequestParam("address") String address,
            @RequestParam("cardnumber") String cardnumber,
            @RequestParam("shopping_cart_revision") Integer cartRevision,
            @RequestParam("expected_total") Integer expectedPrice
    ) {

        if (shoppingCart.getRevision() != cartRevision) {
            request.setAttribute("error", "Der Warenkorb wurde zwischenzeitlich bearbeitet. Daher die Kaufvorgang nicht abgeschlossen werden. Bitte versuchen Sie es erneut.");
            response.setStatus(HttpServletResponse.SC_CONFLICT);
            return "shop/checkout";
        }

        // Must be refetched for persitence.
        user = userRepository.findById(user.id).get();

        CreateOrderAction action = new CreateOrderAction(
                user,
                expectedPrice,
                Address.fromString(address),
                PaymentMethod.fromCreditCardNumber(cardnumber),
                bookingEntryRepository.getByUser(user.id).orElse(BookingAccountEntry.newUser(user)),
                bookingEntryRepository.getByVat().orElse(BookingAccountEntry.newVat()),
                bookingEntryRepository.getByMain().orElse(BookingAccountEntry.newMain())
        );

        for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
            Article article = articleRepository.findById(item.getArticleId()).get();
            action.addArticle(article, item.getAmount(), wbeseRepo.getByArticle(article.id));
        }

        CreateOrderAction.Result result = null;
        try {
            result = action.finish();

            customerOderRepository.save(result.customerOrder);
            bookingRepository.saveAll(result.bookings);
            warehouseBookingRepository.save(result.warehouseBooking);

            shoppingCart.clear();

        } catch (CreateOrderAction.ArticleNotInStockException e) {
            request.setAttribute("error", "Der Artikel '" + e.getArticle().title + "' ist leider nicht mehr in ausreichender Menge verfügbar. Bitte passen Sie die Artikelmenge an.");
            return shopCheckout(session, request, shoppingCart);
        }


        return "shop/checkoutFinish";
    }

    @GetMapping("/checkoutFinish")
    public String shopCheckoutFinishGET() {
        return "shop/checkoutFinish";
    }
}
