package ru.yandex.qe.dispenser.ws.bot;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.inject.Inject;

import com.google.common.collect.Table;
import org.springframework.stereotype.Component;

import ru.yandex.qe.dispenser.domain.QuotaChangeRequest;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.bot.preorder.change.BotPreOrderChangeDao;
import ru.yandex.qe.dispenser.domain.dao.bot.preorder.request.BotPreOrderRequestDao;
import ru.yandex.qe.dispenser.domain.dao.bot.preorder.request.ExtendedPreOrderRequest;

@Component
public class ServersCostHelper {
    private final BotPreOrderRequestDao preOrderRequestDao;
    private final BotPreOrderChangeDao preOrderChangeDao;

    @Inject
    public ServersCostHelper(final BotPreOrderRequestDao preOrderRequestDao, final BotPreOrderChangeDao preOrderChangeDao) {
        this.preOrderRequestDao = preOrderRequestDao;
        this.preOrderChangeDao = preOrderChangeDao;
    }

    public Map<Service, Double> getProviderServersCost(final QuotaChangeRequest request) {
        final Collection<ExtendedPreOrderRequest> preOrderRequests = preOrderRequestDao.getRequestPreorders(request.getId());
        final Map<Long, ExtendedPreOrderRequest> preOrderRequestByPreOrderId = preOrderRequests.stream()
                .collect(Collectors.toMap(ExtendedPreOrderRequest::getPreOrderId, Function.identity()));

        double costMultiplier = 0;
        if (request.getCost() > 0) {
            final double partCostSum = preOrderRequestByPreOrderId.values().stream()
                    .mapToDouble(ExtendedPreOrderRequest::getCost)
                    .sum();
            if (partCostSum > 0) {
                costMultiplier = request.getCost() / partCostSum;
            }
        }

        final Table<Long, Long, Double> preOrderIdsByChangeId = preOrderChangeDao.getPreOrderIdsByChangeId(Collections.singleton(request.getId()));
        final Map<Long, Double> changeSumByPreOrder = new HashMap<>();
        for (final Long preOrderId : preOrderIdsByChangeId.columnKeySet()) {
            double sum = 0;
            for (final Double proportion : preOrderIdsByChangeId.column(preOrderId).values()) {
                sum += proportion;
            }
            changeSumByPreOrder.put(preOrderId, sum);
        }

        final Map<Service, Double> costByService = new HashMap<>();
        for (final QuotaChangeRequest.Change change : request.getChanges()) {
            final Map<Long, Double> changeProportions = preOrderIdsByChangeId.row(change.getId());
            double changeCost = 0;
            for (final Long preOrderId : changeProportions.keySet()) {
                final Double sum = changeSumByPreOrder.get(preOrderId);
                final Double proportion = changeProportions.get(preOrderId);
                final ExtendedPreOrderRequest req = preOrderRequestByPreOrderId.get(preOrderId);
                if (proportion > 0 && req != null) {
                    changeCost += req.getCost() * costMultiplier * proportion / sum;
                }
            }
            final Service service = change.getResource().getService();
            costByService.put(service, costByService.getOrDefault(service, 0.) + changeCost);
        }
        return costByService;
    }
}
