package org.hso.ecommerce.action.cronjob;

import java.sql.Timestamp;
import java.util.HashMap;

import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
import org.hso.ecommerce.api.SupplierService;
import org.hso.ecommerce.api.data.Order;
import org.hso.ecommerce.api.data.OrderConfirmation;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.supplier.ArticleOffer;
import org.hso.ecommerce.entities.supplier.SupplierOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ReorderAction {
    private static final Logger log = LoggerFactory.getLogger(ReorderAction.class);

    private Article article;
    private Integer[] orderedAmounts;
    private Integer undeliveredReorders;
    private int amountInStock;
    private HashMap<ArticleIdentifier, Offer> cheapestOffer;
    private HashMap<ArticleIdentifier, ArticleOffer> articleOffers;

    public ReorderAction(
            Article article, Integer[] orderedAmounts,
            Integer undeliveredReorders,
            int amountInStock,
            HashMap<ArticleIdentifier, Offer> cheapestOffer,
            HashMap<ArticleIdentifier, ArticleOffer> articleOffers
    ) {
        this.article = article;
        this.orderedAmounts = orderedAmounts;
        this.undeliveredReorders = undeliveredReorders;
        this.amountInStock = amountInStock;
        this.cheapestOffer = cheapestOffer;
        this.articleOffers = articleOffers;
    }

    private int null_to_zero(Integer input) {
        return input == null ? 0 : input;
    }

    private int calculateAmountToReorder() {
        // Algorithm as described in the documentation
        int a = null_to_zero(orderedAmounts[0]);
        int b = null_to_zero(orderedAmounts[1]);
        int c = null_to_zero(orderedAmounts[2]);

        int x = Math.max(Math.max(a, b), c);
        int y = Math.min(Math.min(a, b), c);

        int n = 6 * x - 2 * y;
        if (n < 3) {
            n = 3;
        }

        int i = null_to_zero(undeliveredReorders);
        int l = amountInStock;

        return n - i - l;
    }

    public SupplierOrder finish() {
        if (!article.shouldReorder) {
            return null;
        }

        int amount = calculateAmountToReorder();
        if (amount <= 0) {
            return null;
        }

        ArticleIdentifier identifier = new ArticleIdentifier(article.related.manufacturer, article.related.articleNumber);
        Offer offer = cheapestOffer.get(identifier);
        if (offer == null) {
            log.info("Could not order \"" + article.title + "\" because there is no supplier delivering it.");
            return null;
        }

        ArticleOffer articleOffer = articleOffers.get(identifier);
        org.hso.ecommerce.api.data.Article apiArticle = offer.apiSupplier.findArticle(identifier.manufacturer,
                identifier.articleNumber);
        if (apiArticle.pricePerUnitNet > article.reorderMaxPrice) {
            log.info("Could not order \"" + article.title + "\" because it is currently too expensive.");
            return null;
        }

        Order order = new Order();
        order.manufacturer = articleOffer.manufacturer;
        order.articleNumber = articleOffer.articleNumber;
        order.quantity = amount;
        order.maxTotalPriceCentNet = apiArticle.pricePerUnitNet * amount;

        OrderConfirmation confirm = new SupplierService(offer.dbSupplier.apiUrl).order(order);
        SupplierOrder createdOrder = new SupplierOrder();
        createdOrder.created = new Timestamp(System.currentTimeMillis());
        createdOrder.supplier = offer.dbSupplier;
        createdOrder.ordered = articleOffer;
        createdOrder.numberOfUnits = confirm.quantity;
        createdOrder.pricePerUnitNetCent = confirm.pricePerUnitNetCent;
        createdOrder.totalPriceNet = confirm.totalPriceNetCharged;
        return createdOrder;
    }
}
