package de.htwsaar.webshop.service.impl;

import de.htwsaar.webshop.model.MonthlyCatModel;
import de.htwsaar.webshop.repository.entities.Order;
import de.htwsaar.webshop.repository.entities.OrderItem;
import de.htwsaar.webshop.service.OrderService;
import de.htwsaar.webshop.service.StatisticsService;
import de.htwsaar.webshop.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Map;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StatisticsServiceImpl implements StatisticsService {
    private final OrderService orderService;

    @Autowired
    public StatisticsServiceImpl(OrderService orderService) {
        this.orderService = orderService;
    }

    //don't ask pls
    //returns Map<unix milli timestamp, Map<Category, T>>
    private <T extends Number> MonthlyCatModel<T> getMonthCategoryMap(Function<OrderItem, T> mappingFunction,
                                                                      BinaryOperator<T> reduceFunction) {
        return new MonthlyCatModel<>(
                orderService.getTimeSortedOrders(TimeUtil.nowMonthsAgo(12), 12).entrySet().stream()
                        .map(entry -> Map.entry(entry.getKey(),
                                entry.getValue().stream()
                                        .map(Order::getOrderItems)
                                        .reduce(new ArrayList<>(), (l, r) -> {
                                            l.addAll(r);
                                            return l;
                                        })
                                        .stream()
                                        .map(orderItem -> Map.entry(orderItem.getArticle().getCategory(), mappingFunction.apply(orderItem)))
                                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, reduceFunction))
                        ))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
        );
    }

    @Override
    public MonthlyCatModel<Integer> getSalesVolume() {
        return getMonthCategoryMap(OrderItem::getAmount, Integer::sum);
    }

    @Override
    public MonthlyCatModel<Integer> getSalesRevenue() {
        return getMonthCategoryMap(item -> item.getArticle().getPrice100(), Integer::sum);
    }
}
