package org.hso.ecommerce.controller.cronjob;

import org.hso.ecommerce.action.warehouse.CalculateWarehouseStatsAction;
import org.hso.ecommerce.entities.dashboard.DashboardSummary;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
import org.hso.ecommerce.repos.user.UserRepository;
import org.hso.ecommerce.repos.warehouse.SlotRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class DashboardCronjob implements ICronjob {

    @Autowired
    private SlotRepository slotRepository = null;

    @Autowired
    private UserRepository userRepository = null;

    @Autowired
    private WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;

    @Autowired
    private CustomerOrderRepository customerOrderRepository = null;

    @Override
    public Calendar nextExecution(Calendar reference) {
        reference.add(Calendar.DAY_OF_MONTH, 1);
        reference.set(Calendar.HOUR_OF_DAY, 0);
        reference.set(Calendar.MINUTE, 0);
        reference.set(Calendar.SECOND, 0);
        reference.set(Calendar.MILLISECOND, 0);
        return reference;
    }

    @Override
    public Calendar previousExecution(Calendar reference) {
        reference.set(Calendar.HOUR_OF_DAY, 0);
        reference.set(Calendar.MINUTE, 0);
        reference.set(Calendar.SECOND, 0);
        reference.set(Calendar.MILLISECOND, 0);
        return reference;
    }

    @Override
    public void executeAt(Calendar time, CronjobController controller) {

        Calendar oneDayBefore = (Calendar) time.clone();
        oneDayBefore.add(Calendar.DAY_OF_MONTH, -1);

        DashboardSummary dashboardSummary = new DashboardSummary();

        List<WarehouseBookingPositionSlotEntry> entries = slotRepository.findAll().stream().map(
                s -> warehouseBookingPositionSlotEntryRepository
                        .getBySlotNum(s.slotNum)
                        .orElseGet(() -> WarehouseBookingPositionSlotEntry.empty(null, s))
        ).collect(Collectors.toList());
        CalculateWarehouseStatsAction.WarehouseStats warehouseStats = new CalculateWarehouseStatsAction(entries).finish();

        dashboardSummary.created = new java.sql.Date(time.getTimeInMillis());
        dashboardSummary.todaysCustomersOrders = nullToZero(getSales(oneDayBefore, time));
        dashboardSummary.todaysNewCustomers = nullToZero(getNewUsers(oneDayBefore, time));
        dashboardSummary.todaysWarehouseCapacity = warehouseStats.efficiency;
        dashboardSummary.currentWarehouseCapacity = warehouseStats.ratioUsedSlots;
        dashboardSummary.todaysSalesCent = nullToZero(getTurnover(oneDayBefore, time));

        controller.dashboardSummaryRepository.save(dashboardSummary);
    }

    @Override
    public String getDisplayName() {
        return "Dashboard refresh";
    }

    private Integer getSales(Calendar begin, Calendar end) {
        return customerOrderRepository.countOrdersInTimespan(
                new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
    }

    private Integer getTurnover(Calendar begin, Calendar end) {
        return customerOrderRepository.countTurnoverInTimespan(
                new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
    }

    private Integer getNewUsers(Calendar begin, Calendar end) {
        return userRepository.countUsersInTimespan(
                new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
    }

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