package org.hso.ecommerce.action.warehouse;

import org.hso.ecommerce.entities.booking.BookingReason;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;

import java.sql.Timestamp;
import java.util.Date;
import java.util.Optional;

public class CreateManuelBookingAction {

    private Article article;
    private int amount;
    private Optional<WarehouseBookingPositionSlotEntry> source;
    private Optional<WarehouseBookingPositionSlotEntry> destination;
    private String reason;

    public CreateManuelBookingAction(Article article, int amount, Optional<WarehouseBookingPositionSlotEntry> source, Optional<WarehouseBookingPositionSlotEntry> destination, String reason) {
        this.article = article;
        this.amount = amount;
        this.source = source;
        this.destination = destination;
        this.reason = reason;
    }

    public WarehouseBooking finish() throws ArticleSlotConstraintFailedException {
        WarehouseBooking booking = new WarehouseBooking();
        booking.created = new Timestamp(new Date().getTime());
        booking.reason = new BookingReason(reason);

        if (source.isPresent()) {

            if (source.get().article.id != article.id) {
                throw new ArticleSlotConstraintArticleTypeFailedException();
            }

            WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
            bookingPosition.booking = booking;

            bookingPosition.article = article;
            bookingPosition.amount = -amount;
            bookingPosition.slotEntry = source.get().copyAddAmount(-amount);

            if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
                throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
            }

            booking.positions.add(bookingPosition);
        }

        if (destination.isPresent()) {

            if (destination.get().article.id != article.id) {
                throw new ArticleSlotConstraintArticleTypeFailedException();
            }

            WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
            bookingPosition.booking = booking;

            bookingPosition.article = article;
            bookingPosition.amount = amount;
            bookingPosition.slotEntry = destination.get().copyAddAmount(amount);

            if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
                throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
            }

            booking.positions.add(bookingPosition);
        }

        return booking;
    }

    public static class ArticleSlotConstraintFailedException extends Exception {
        public ArticleSlotConstraintFailedException(String s) {
            super(s);
        }

        public ArticleSlotConstraintFailedException() {
            super("The quantity of article can only be set in bounds.");
        }
    }

    public static class ArticleSlotConstraintArticleTypeFailedException extends ArticleSlotConstraintFailedException {
        public ArticleSlotConstraintArticleTypeFailedException() {
            super("The Article in the slot entry does not match.");
        }
    }
}
