package de.avatic.lcc.service.calculation.execution.steps;

import de.avatic.lcc.model.calculation.InventoryCostResult;
import de.avatic.lcc.model.db.packaging.PackagingDimension;
import de.avatic.lcc.model.db.premises.Premise;
import de.avatic.lcc.model.db.premises.route.Destination;
import de.avatic.lcc.model.db.properties.CountryPropertyMappingId;
import de.avatic.lcc.model.db.properties.SystemPropertyMappingId;
import de.avatic.lcc.model.db.utils.DimensionUnit;
import de.avatic.lcc.repositories.country.CountryPropertyRepository;
import de.avatic.lcc.repositories.properties.PropertyRepository;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;

@Service
public class InventoryCostCalculationService {


    private final ShippingFrequencyCalculationService shippingFrequencyCalculationService;
    private final PropertyRepository propertyRepository;
    private final CountryPropertyRepository countryPropertyRepository;
    private final PremiseToHuService premiseToHuService;

    public InventoryCostCalculationService(ShippingFrequencyCalculationService shippingFrequencyCalculationService, PropertyRepository propertyRepository, CountryPropertyRepository countryPropertyRepository, PremiseToHuService premiseToHuService) {
        this.shippingFrequencyCalculationService = shippingFrequencyCalculationService;
        this.propertyRepository = propertyRepository;
        this.countryPropertyRepository = countryPropertyRepository;
        this.premiseToHuService = premiseToHuService;
    }

    public InventoryCostResult doCalculation(Integer setId, Premise premise, Destination destination, BigDecimal leadTime) {


        var fcaFee = BigDecimal.ZERO;

        if (premise.getFcaEnabled()) {
            var fcaProperty = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.FCA_FEE).orElseThrow();
            var fcaShare = Double.parseDouble(fcaProperty.getCurrentValue());
            fcaFee = BigDecimal.valueOf(fcaShare).multiply(premise.getMaterialCost());
        }

        var hu = premiseToHuService.createHuFromPremise(premise);
        double huAnnualAmount = BigDecimal.valueOf(destination.getAnnualAmount()).divide(BigDecimal.valueOf(hu.getContentUnitCount()),0, RoundingMode.UP ).doubleValue();

        var safetyDays = BigDecimal.valueOf(Integer.parseInt(countryPropertyRepository.getByMappingIdAndCountryId(CountryPropertyMappingId.SAFETY_STOCK, setId, premise.getCountryId()).orElseThrow().getCurrentValue()));
        var workdays = BigDecimal.valueOf(Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.WORKDAYS, setId).orElseThrow().getCurrentValue()));
        var paymentTerms = BigDecimal.valueOf(Integer.parseInt(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.PAYMENT_TERMS, setId).orElseThrow().getCurrentValue()));
        var interestRate = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.INTEREST_RATE, setId).orElseThrow().getCurrentValue()));

        var annualAmount = BigDecimal.valueOf(destination.getAnnualAmount().doubleValue());
        var dailyAmount = annualAmount.divide(BigDecimal.valueOf(365), 10, RoundingMode.HALF_UP);
        var workdayAmount = annualAmount.divide(workdays, 10, RoundingMode.HALF_UP);

        var opStock = (annualAmount.divide(BigDecimal.valueOf(Math.max(shippingFrequencyCalculationService.doCalculation(setId, huAnnualAmount),1)), 10, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(.5)));
        var safetyStock = safetyDays.multiply(workdayAmount);
        var stockedInventory = opStock.add(safetyStock);
        var inTransportStock = dailyAmount.multiply(leadTime);
        var stockBeforePayment = dailyAmount.multiply(paymentTerms);

        var capitalCostStock = stockedInventory.add(inTransportStock).subtract(stockBeforePayment);
        var storageCostStock = roundToHu(hu, safetyStock.add(opStock));

        var capitalCost = capitalCostStock.multiply(interestRate).multiply(premise.getMaterialCost().add(fcaFee));
        var storageCost = storageCostStock.multiply(getSpaceCostPerHu(setId, hu)).multiply(BigDecimal.valueOf(365));


        return new InventoryCostResult(opStock, safetyStock, stockedInventory, inTransportStock, stockBeforePayment, capitalCost, storageCost, safetyDays );

    }

    private BigDecimal getSpaceCostPerHu(Integer setId, PackagingDimension hu) {
        var spaceCost = BigDecimal.valueOf(Double.parseDouble(propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.SPACE_COST, setId).orElseThrow().getCurrentValue()));
        var spaceCostPerHu = BigDecimal.valueOf(hu.getFloorArea(DimensionUnit.M)*hu.getRoundedHeight(DimensionUnit.M)).multiply(spaceCost);
        return spaceCostPerHu;
    }

    private BigDecimal roundToHu(PackagingDimension hu, BigDecimal safetyStock) {
       return safetyStock.divide(BigDecimal.valueOf(hu.getContentUnitCount()), 0, RoundingMode.UP);
    }



}
