/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package io.mifos.individuallending.internal.service.costcomponent;

import com.google.common.collect.Sets;
import io.mifos.core.lang.DateConverter;
import io.mifos.individuallending.IndividualLendingPatternFactory;
import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPayment;
import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
import io.mifos.individuallending.api.v1.domain.workflow.Action;
import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
import io.mifos.portfolio.api.v1.domain.CostComponent;
import io.mifos.portfolio.api.v1.domain.Payment;
import io.mifos.portfolio.api.v1.domain.RequiredAccountAssignment;

import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Myrle Krantz
 */
public class PaymentBuilder {
  private final RunningBalances prePaymentBalances;
  private final Map<ChargeDefinition, CostComponent> costComponents;

  private final Map<String, BigDecimal> balanceAdjustments;
  private final boolean accrualAccounting;

  PaymentBuilder(final RunningBalances prePaymentBalances,
                 final boolean accrualAccounting) {
    this.prePaymentBalances = prePaymentBalances;
    this.costComponents = new HashMap<>();
    this.balanceAdjustments = new HashMap<>();
    this.accrualAccounting = accrualAccounting;
  }

  private Map<String, BigDecimal> copyBalanceAdjustments() {
    return balanceAdjustments.entrySet().stream()
        .filter(x -> x.getValue().compareTo(BigDecimal.ZERO) != 0)
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  }

  public Payment buildPayment(
      final Action action,
      final Set<String> forAccountDesignators,
      final @Nullable LocalDate forDate)
  {
    if (!forAccountDesignators.isEmpty()) {
      final Stream<Map.Entry<ChargeDefinition, CostComponent>> costComponentStream = stream()
          .filter(costComponentEntry -> chargeReferencesAccountDesignators(
              costComponentEntry.getKey(),
              action,
              forAccountDesignators));

      final List<CostComponent> costComponentList = costComponentStream
          .map(costComponentEntry -> new CostComponent(
              costComponentEntry.getKey().getIdentifier(),
              costComponentEntry.getValue().getAmount()))
          .collect(Collectors.toList());

      final Payment ret = new Payment(costComponentList, copyBalanceAdjustments());
      ret.setDate(forDate == null ? null : DateConverter.toIsoString(forDate.atStartOfDay()));
      return ret;
    }
    else {
      return buildPayment(forDate);
    }

  }

  private Payment buildPayment(final @Nullable LocalDate forDate) {
    final Stream<Map.Entry<ChargeDefinition, CostComponent>> costComponentStream  = stream();

    final List<CostComponent> costComponentList = costComponentStream
        .map(costComponentEntry -> new CostComponent(
            costComponentEntry.getKey().getIdentifier(),
            costComponentEntry.getValue().getAmount()))
        .collect(Collectors.toList());

    final Payment ret = new Payment(costComponentList, copyBalanceAdjustments());
    ret.setDate(forDate == null ? null : DateConverter.toIsoString(forDate.atStartOfDay()));
    return ret;
  }

  public PlannedPayment accumulatePlannedPayment(
      final SimulatedRunningBalances balances,
      final @Nullable LocalDate forDate) {
    final Payment payment = buildPayment(forDate);
    balanceAdjustments.forEach(balances::adjustBalance);
    final Map<String, BigDecimal> balancesCopy = balances.snapshot();

    return new PlannedPayment(payment, balancesCopy);
  }

  public Map<String, BigDecimal> getBalanceAdjustments() {
    return balanceAdjustments;
  }

  public BigDecimal getBalanceAdjustment(final String... accountDesignators) {
    return Arrays.stream(accountDesignators)
        .map(accountDesignator -> balanceAdjustments.getOrDefault(accountDesignator, BigDecimal.ZERO))
        .reduce(BigDecimal.ZERO, BigDecimal::add);
  }

  void adjustBalances(
      final Action action,
      final ChargeDefinition chargeDefinition,
      final BigDecimal chargeAmount) {
    BigDecimal adjustedChargeAmount;
    if (this.accrualAccounting && chargeIsAccrued(chargeDefinition)) {
      if (Action.valueOf(chargeDefinition.getAccrueAction()) == action) {
        adjustedChargeAmount = getMaxCharge(chargeDefinition.getFromAccountDesignator(), chargeDefinition.getAccrualAccountDesignator(), chargeAmount);

        this.addToBalance(chargeDefinition.getFromAccountDesignator(), adjustedChargeAmount.negate());
        this.addToBalance(chargeDefinition.getAccrualAccountDesignator(), adjustedChargeAmount);
      } else if (Action.valueOf(chargeDefinition.getChargeAction()) == action) {
        adjustedChargeAmount = getMaxCharge(chargeDefinition.getAccrualAccountDesignator(), chargeDefinition.getToAccountDesignator(), chargeAmount);

        this.addToBalance(chargeDefinition.getAccrualAccountDesignator(), adjustedChargeAmount.negate());
        this.addToBalance(chargeDefinition.getToAccountDesignator(), adjustedChargeAmount);

        addToCostComponent(chargeDefinition, adjustedChargeAmount);
      }
    }
    else if (Action.valueOf(chargeDefinition.getChargeAction()) == action) {
      adjustedChargeAmount = getMaxCharge(chargeDefinition.getFromAccountDesignator(), chargeDefinition.getToAccountDesignator(), chargeAmount);

      this.addToBalance(chargeDefinition.getFromAccountDesignator(), adjustedChargeAmount.negate());
      this.addToBalance(chargeDefinition.getToAccountDesignator(), adjustedChargeAmount);

      addToCostComponent(chargeDefinition, adjustedChargeAmount);
    }
  }

  private BigDecimal getMaxCharge(
      final String fromAccountDesignator,
      final String toAccountDesignator,
      final BigDecimal plannedCharge) {
    final BigDecimal expectedImpactOnDebitAccount = plannedCharge.subtract(this.getBalanceAdjustment(fromAccountDesignator));
    final BigDecimal maxImpactOnDebitAccount = prePaymentBalances.getMaxDebit(fromAccountDesignator, expectedImpactOnDebitAccount);
    final BigDecimal maxDebit = (!fromAccountDesignator.equals(AccountDesignators.PRODUCT_LOSS_ALLOWANCE)) ?
        maxImpactOnDebitAccount.add(this.getBalanceAdjustment(fromAccountDesignator)).max(BigDecimal.ZERO) :
        maxImpactOnDebitAccount.add(this.getBalanceAdjustment(fromAccountDesignator));

    final BigDecimal expectedImpactOnCreditAccount = plannedCharge.add(this.getBalanceAdjustment(toAccountDesignator));
    final BigDecimal maxImpactOnCreditAccount = prePaymentBalances.getMaxCredit(toAccountDesignator, expectedImpactOnCreditAccount);
    final BigDecimal maxCredit = (!toAccountDesignator.equals(AccountDesignators.GENERAL_LOSS_ALLOWANCE)) ?
        maxImpactOnCreditAccount.subtract(this.getBalanceAdjustment(toAccountDesignator)).max(BigDecimal.ZERO) :
        maxImpactOnCreditAccount.subtract(this.getBalanceAdjustment(toAccountDesignator));
    return maxCredit.min(maxDebit);
  }

  private static boolean chargeIsAccrued(final ChargeDefinition chargeDefinition) {
    return chargeDefinition.getAccrualAccountDesignator() != null && chargeDefinition.getAccrueAction() != null;
  }

  private void addToBalance(
      final String accountDesignator,
      final BigDecimal chargeAmount) {
    final BigDecimal currentAdjustment = balanceAdjustments.getOrDefault(accountDesignator, BigDecimal.ZERO);
    final BigDecimal newAdjustment = currentAdjustment.add(chargeAmount);
    balanceAdjustments.put(accountDesignator, newAdjustment);
  }

  private void addToCostComponent(
      final ChargeDefinition chargeDefinition,
      final BigDecimal amount) {
    final CostComponent costComponent = costComponents
        .computeIfAbsent(chargeDefinition, PaymentBuilder::constructEmptyCostComponent);
    costComponent.setAmount(costComponent.getAmount().add(amount));
  }

  private Stream<Map.Entry<ChargeDefinition, CostComponent>> stream() {
    return costComponents.entrySet().stream()
        .filter(costComponentEntry -> costComponentEntry.getValue().getAmount().compareTo(BigDecimal.ZERO) != 0);
  }


  private static boolean chargeReferencesAccountDesignators(
      final ChargeDefinition chargeDefinition,
      final Action action,
      final Set<String> forAccountDesignators) {
    final Set<String> accountsToCompare = Sets.newHashSet(
        chargeDefinition.getFromAccountDesignator(),
        chargeDefinition.getToAccountDesignator()
    );
    if (chargeDefinition.getAccrualAccountDesignator() != null)
      accountsToCompare.add(chargeDefinition.getAccrualAccountDesignator());

    final Set<String> expandedForAccountDesignators = expandAccountDesignators(forAccountDesignators);

    return !Sets.intersection(accountsToCompare, expandedForAccountDesignators).isEmpty();
  }

  static Set<String> expandAccountDesignators(final Set<String> accountDesignators) {
    final Set<RequiredAccountAssignment> accountAssignmentsRequired = IndividualLendingPatternFactory.individualLendingPattern().getAccountAssignmentsRequired();
    final Map<String, List<RequiredAccountAssignment>> accountAssignmentsByGroup = accountAssignmentsRequired.stream()
        .filter(x -> x.getGroup() != null)
        .collect(Collectors.groupingBy(RequiredAccountAssignment::getGroup, Collectors.toList()));
    final Set<String> groupExpansions = accountDesignators.stream()
        .flatMap(accountDesignator -> {
          final List<RequiredAccountAssignment> group = accountAssignmentsByGroup.get(accountDesignator);
          if (group != null)
            return group.stream();
          else
            return Stream.empty();
        })
        .map(RequiredAccountAssignment::getAccountDesignator)
        .collect(Collectors.toSet());
    final Set<String> ret = new HashSet<>(accountDesignators);
    ret.addAll(groupExpansions);
    return ret;
  }

  private static CostComponent constructEmptyCostComponent(final ChargeDefinition chargeDefinition) {
    final CostComponent ret = new CostComponent();
    ret.setChargeIdentifier(chargeDefinition.getIdentifier());
    ret.setAmount(BigDecimal.ZERO);
    return ret;
  }
}
