/*
 * Copyright 2017 The Mifos Initiative.
 *
 * Licensed 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.portfolio;

import com.google.gson.Gson;
import io.mifos.accounting.api.v1.domain.AccountType;
import io.mifos.accounting.api.v1.domain.Creditor;
import io.mifos.accounting.api.v1.domain.Debtor;
import io.mifos.core.api.util.ApiFactory;
import io.mifos.core.lang.DateConverter;
import io.mifos.individuallending.api.v1.domain.caseinstance.CaseParameters;
import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
import io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers;
import io.mifos.individuallending.api.v1.domain.product.ChargeProportionalDesignator;
import io.mifos.individuallending.api.v1.domain.workflow.Action;
import io.mifos.individuallending.api.v1.events.IndividualLoanCommandEvent;
import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
import io.mifos.portfolio.api.v1.domain.*;
import io.mifos.portfolio.api.v1.events.BalanceSegmentSetEvent;
import io.mifos.portfolio.api.v1.events.ChargeDefinitionEvent;
import io.mifos.portfolio.api.v1.events.EventConstants;
import io.mifos.rhythm.spi.v1.client.BeatListener;
import io.mifos.rhythm.spi.v1.domain.BeatPublish;
import io.mifos.rhythm.spi.v1.events.BeatPublishEvent;
import org.assertj.core.util.Sets;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.IntStream;

import static io.mifos.portfolio.Fixture.MINOR_CURRENCY_UNIT_DIGITS;

/**
 * @author Myrle Krantz
 */
public class TestAccountingInteractionInLoanWorkflow extends AbstractPortfolioTest {
  private static final BigDecimal PROCESSING_FEE_AMOUNT = BigDecimal.valueOf(100_00, MINOR_CURRENCY_UNIT_DIGITS);
  private static final BigDecimal LOAN_ORIGINATION_FEE_AMOUNT = BigDecimal.valueOf(100_00, MINOR_CURRENCY_UNIT_DIGITS);
  private static final BigDecimal DISBURSEMENT_FEE_LOWER_RANGE_AMOUNT = BigDecimal.valueOf(10_00, MINOR_CURRENCY_UNIT_DIGITS);
  private static final BigDecimal DISBURSEMENT_FEE_UPPER_RANGE_AMOUNT = BigDecimal.valueOf(1_00, MINOR_CURRENCY_UNIT_DIGITS);
  private static final String DISBURSEMENT_RANGES = "disbursement_ranges";
  private static final String DISBURSEMENT_LOWER_RANGE = "smaller";
  private static final String DISBURSEMENT_UPPER_RANGE = "larger";
  private static final String UPPER_RANGE_DISBURSEMENT_FEE_ID = ChargeIdentifiers.DISBURSEMENT_FEE_ID + "2";

  private BeatListener portfolioBeatListener;

  private Product product = null;
  private Case customerCase = null;
  private TaskDefinition taskDefinition = null;
  private String customerLoanPrincipalIdentifier = null;
  private String customerLoanInterestIdentifier = null;
  private String customerLoanFeeIdentifier = null;

  private BigDecimal expectedCurrentBalance = null;
  private BigDecimal interestAccrued = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
  private BigDecimal nonLateFees = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);


  @Before
  public void prepBeatListener() {
    portfolioBeatListener = new ApiFactory(logger).create(BeatListener.class, testEnvironment.serverURI());
  }

  @Test
  public void workflowTerminatingInApplicationDenial() throws InterruptedException {
    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4DenyCase();
  }

  @Test
  public void workflowTerminatingInEarlyLoanPayoff() throws InterruptedException {
    final LocalDateTime today = midnightToday();

    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4ApproveCase();
    step5Disburse(
        BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
    step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), null);
    step7PaybackPartialAmount(expectedCurrentBalance, today, 0, BigDecimal.ZERO);
    step8Close();
  }

  @Test
  public void workflowWithTwoUnequalDisbursals() throws InterruptedException {
    final LocalDateTime today = midnightToday();

    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4ApproveCase();
    step5Disburse(
        BigDecimal.valueOf(500_00, MINOR_CURRENCY_UNIT_DIGITS),
        ChargeIdentifiers.DISBURSEMENT_FEE_ID, BigDecimal.valueOf(10_00, MINOR_CURRENCY_UNIT_DIGITS));
    step5Disburse(
        BigDecimal.valueOf(1_500_00, MINOR_CURRENCY_UNIT_DIGITS),
        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(15_00, MINOR_CURRENCY_UNIT_DIGITS));
    step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), null);
    step7PaybackPartialAmount(expectedCurrentBalance, today, 0, BigDecimal.ZERO);
    step8Close();
  }

  @Test
  public void workflowWithTwoNearlyEqualRepayments() throws InterruptedException {
    final LocalDateTime today = midnightToday();

    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4ApproveCase();
    step5Disburse(
        BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));
    step6CalculateInterestAccrualAndCheckForLateness(midnightToday(), null);
    final BigDecimal repayment1 = expectedCurrentBalance.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_EVEN);
    step7PaybackPartialAmount(
        repayment1.setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN),
        today,
        0, BigDecimal.ZERO);
    step7PaybackPartialAmount(expectedCurrentBalance, today, 0, BigDecimal.ZERO);
    step8Close();
  }

  @Test
  public void workflowWithNegativePaymentSize() throws InterruptedException {
    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4ApproveCase();
    try {
      step5Disburse(BigDecimal.valueOf(-2).setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN),
          UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN));
      Assert.fail("Expected an IllegalArgumentException.");
    }
    catch (IllegalArgumentException ignored) { }
  }

  @Test
  public void workflowWithNormalRepayment() throws InterruptedException {
    final LocalDateTime today = midnightToday();

    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4ApproveCase();
    step5Disburse(
        BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));

    int week = 0;
    final List<BigDecimal> repayments = new ArrayList<>();
    while (expectedCurrentBalance.compareTo(BigDecimal.ZERO) > 0) {
      logger.info("Simulating week {}. Expected current balance {}.", week, expectedCurrentBalance);
      step6CalculateInterestAndCheckForLatenessForWeek(today, week);
      final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today, (week+1)*7);
      repayments.add(nextRepaymentAmount);
      step7PaybackPartialAmount(nextRepaymentAmount, today, (week+1)*7, BigDecimal.ZERO);
      week++;
    }

    checkRepaymentVariance(repayments);


    step8Close();
  }

  private void checkRepaymentVariance(List<BigDecimal> repayments) {
    final BigDecimal minPayment = repayments.stream().min(BigDecimal::compareTo).orElseThrow(IllegalStateException::new);
    final BigDecimal maxPayment = repayments.stream().max(BigDecimal::compareTo).orElseThrow(IllegalStateException::new);
    final BigDecimal delta = maxPayment.subtract(minPayment).abs();
    Assert.assertTrue("Payments vary too much. Payments are " + repayments,
        delta.divide(maxPayment, BigDecimal.ROUND_HALF_EVEN).compareTo(BigDecimal.valueOf(0.01)) <= 0);
  }

  @Test
  public void workflowWithOneLateRepayment() throws InterruptedException {
    final LocalDateTime today = midnightToday();

    step1CreateProduct();
    step2CreateCase();
    step3OpenCase();
    step4ApproveCase();
    step5Disburse(
        BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS),
        UPPER_RANGE_DISBURSEMENT_FEE_ID, BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS));

    int week = 0;
    final int weekOfLateRepayment = 3;
    final List<BigDecimal> repayments = new ArrayList<>();
    while (expectedCurrentBalance.compareTo(BigDecimal.ZERO) > 0) {
      logger.info("Simulating week {}. Expected current balance {}.", week, expectedCurrentBalance);
      if (week == weekOfLateRepayment) {
        final BigDecimal lateFee = BigDecimal.valueOf(31_18, MINOR_CURRENCY_UNIT_DIGITS);
        step6CalculateInterestAndCheckForLatenessForRangeOfDays(
            today,
            (week * 7) + 1,
            (week + 1) * 7 + 2,
            8,
            lateFee);
        final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today, (week + 1) * 7 + 2);
        repayments.add(nextRepaymentAmount);
        step7PaybackPartialAmount(nextRepaymentAmount, today, (week + 1) * 7 + 2, lateFee);
      }
      else {
        step6CalculateInterestAndCheckForLatenessForWeek(today, week);
        final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(today, (week + 1) * 7);
        repayments.add(nextRepaymentAmount);
        step7PaybackPartialAmount(nextRepaymentAmount, today, (week + 1) * 7, BigDecimal.ZERO);
      }
      week++;
    }

    repayments.remove(3);

    checkRepaymentVariance(repayments);

    step8Close();
  }

  private BigDecimal findNextRepaymentAmount(
      final LocalDateTime referenceDate,
      final int dayNumber) {
    AccountingFixture.mockBalance(customerLoanPrincipalIdentifier, expectedCurrentBalance);

    final Payment nextPayment = portfolioManager.getCostComponentsForAction(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.ACCEPT_PAYMENT.name(),
        null,
        null,
        DateConverter.toIsoString(referenceDate.plusDays(dayNumber)));
    return nextPayment.getCostComponents().stream().filter(x -> x.getChargeIdentifier().equals(ChargeIdentifiers.REPAY_PRINCIPAL_ID)).findFirst()
        .orElseThrow(() -> new IllegalArgumentException("return missing repayment charge."))
        .getAmount();
  }

  //Create product and set charges to fixed fees.
  private void step1CreateProduct() throws InterruptedException {
    logger.info("step1CreateProduct");
    product = createProduct();

    final BalanceSegmentSet balanceSegmentSet = new BalanceSegmentSet();
    balanceSegmentSet.setIdentifier(DISBURSEMENT_RANGES);
    balanceSegmentSet.setSegmentIdentifiers(Arrays.asList(DISBURSEMENT_LOWER_RANGE, DISBURSEMENT_UPPER_RANGE));
    balanceSegmentSet.setSegments(Arrays.asList(BigDecimal.ZERO, BigDecimal.valueOf(1_000_0000, 4)));
    portfolioManager.createBalanceSegmentSet(product.getIdentifier(), balanceSegmentSet);
    Assert.assertTrue(this.eventRecorder.wait(EventConstants.POST_BALANCE_SEGMENT_SET, new BalanceSegmentSetEvent(product.getIdentifier(), balanceSegmentSet.getIdentifier())));

    setFeeToFixedValue(product.getIdentifier(), ChargeIdentifiers.PROCESSING_FEE_ID, PROCESSING_FEE_AMOUNT);
    setFeeToFixedValue(product.getIdentifier(), ChargeIdentifiers.LOAN_ORIGINATION_FEE_ID, LOAN_ORIGINATION_FEE_AMOUNT);

    final ChargeDefinition lowerRangeDisbursementFeeChargeDefinition
        = portfolioManager.getChargeDefinition(product.getIdentifier(), ChargeIdentifiers.DISBURSEMENT_FEE_ID);
    lowerRangeDisbursementFeeChargeDefinition.setChargeMethod(ChargeDefinition.ChargeMethod.FIXED);
    lowerRangeDisbursementFeeChargeDefinition.setAmount(DISBURSEMENT_FEE_LOWER_RANGE_AMOUNT);
    lowerRangeDisbursementFeeChargeDefinition.setProportionalTo(ChargeProportionalDesignator.REQUESTED_DISBURSEMENT_DESIGNATOR.getValue());
    lowerRangeDisbursementFeeChargeDefinition.setForSegmentSet(DISBURSEMENT_RANGES);
    lowerRangeDisbursementFeeChargeDefinition.setFromSegment(DISBURSEMENT_LOWER_RANGE);
    lowerRangeDisbursementFeeChargeDefinition.setToSegment(DISBURSEMENT_LOWER_RANGE);

    portfolioManager.changeChargeDefinition(product.getIdentifier(), ChargeIdentifiers.DISBURSEMENT_FEE_ID, lowerRangeDisbursementFeeChargeDefinition);
    Assert.assertTrue(this.eventRecorder.wait(EventConstants.PUT_CHARGE_DEFINITION,
        new ChargeDefinitionEvent(product.getIdentifier(), ChargeIdentifiers.DISBURSEMENT_FEE_ID)));

    final ChargeDefinition upperRangeDisbursementFeeChargeDefinition = new ChargeDefinition();
    upperRangeDisbursementFeeChargeDefinition.setIdentifier(UPPER_RANGE_DISBURSEMENT_FEE_ID);
    upperRangeDisbursementFeeChargeDefinition.setName(UPPER_RANGE_DISBURSEMENT_FEE_ID);
    upperRangeDisbursementFeeChargeDefinition.setDescription(lowerRangeDisbursementFeeChargeDefinition.getDescription());
    upperRangeDisbursementFeeChargeDefinition.setFromAccountDesignator(lowerRangeDisbursementFeeChargeDefinition.getFromAccountDesignator());
    upperRangeDisbursementFeeChargeDefinition.setToAccountDesignator(lowerRangeDisbursementFeeChargeDefinition.getToAccountDesignator());
    upperRangeDisbursementFeeChargeDefinition.setAccrualAccountDesignator(lowerRangeDisbursementFeeChargeDefinition.getAccrualAccountDesignator());
    upperRangeDisbursementFeeChargeDefinition.setAccrueAction(lowerRangeDisbursementFeeChargeDefinition.getAccrueAction());
    upperRangeDisbursementFeeChargeDefinition.setChargeAction(lowerRangeDisbursementFeeChargeDefinition.getChargeAction());
    upperRangeDisbursementFeeChargeDefinition.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
    upperRangeDisbursementFeeChargeDefinition.setAmount(DISBURSEMENT_FEE_UPPER_RANGE_AMOUNT);
    upperRangeDisbursementFeeChargeDefinition.setProportionalTo(ChargeProportionalDesignator.REQUESTED_DISBURSEMENT_DESIGNATOR.getValue());
    upperRangeDisbursementFeeChargeDefinition.setForSegmentSet(DISBURSEMENT_RANGES);
    upperRangeDisbursementFeeChargeDefinition.setFromSegment(DISBURSEMENT_UPPER_RANGE);
    upperRangeDisbursementFeeChargeDefinition.setToSegment(DISBURSEMENT_UPPER_RANGE);

    portfolioManager.createChargeDefinition(product.getIdentifier(), upperRangeDisbursementFeeChargeDefinition);
    Assert.assertTrue(this.eventRecorder.wait(EventConstants.POST_CHARGE_DEFINITION,
        new ChargeDefinitionEvent(product.getIdentifier(), UPPER_RANGE_DISBURSEMENT_FEE_ID)));

    taskDefinition = createTaskDefinition(product);

    portfolioManager.enableProduct(product.getIdentifier(), true);
    Assert.assertTrue(this.eventRecorder.wait(EventConstants.PUT_PRODUCT_ENABLE, product.getIdentifier()));
  }

  private void step2CreateCase() throws InterruptedException {
    logger.info("step2CreateCase");
    final CaseParameters caseParameters = Fixture.createAdjustedCaseParameters(x ->
        x.setPaymentCycle(new PaymentCycle(ChronoUnit.WEEKS, 1, null, null, null))
    );
    final String caseParametersAsString = new Gson().toJson(caseParameters);
    customerCase = createAdjustedCase(product.getIdentifier(), x -> x.setParameters(caseParametersAsString));

    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.OPEN);
  }

  //Open the case and accept a processing fee.
  private void step3OpenCase() throws InterruptedException {
    logger.info("step3OpenCase");
    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.OPEN,
        null,
        null);
    checkStateTransfer(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.OPEN,
        Collections.singletonList(assignEntryToTeller()),
        IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE,
        Case.State.PENDING);
    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPROVE, Action.DENY);
  }


  //Deny the case. Once this is done, no more actions are possible for the case.
  private void step4DenyCase() throws InterruptedException {
    logger.info("step4DenyCase");
    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.DENY,
        null,
        null);
    checkStateTransfer(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.DENY,
        Collections.singletonList(assignEntryToTeller()),
        IndividualLoanEventConstants.DENY_INDIVIDUALLOAN_CASE,
        Case.State.CLOSED);
    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier());
  }


  //Approve the case, accept a loan origination fee, and prepare to disburse the loan by earmarking the funds.
  private void step4ApproveCase() throws InterruptedException {
    logger.info("step4ApproveCase");

    markTaskExecuted(product, customerCase, taskDefinition);

    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.APPROVE,
        null,
        null);
    checkStateTransfer(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.APPROVE,
        Collections.singletonList(assignEntryToTeller()),
        IndividualLoanEventConstants.APPROVE_INDIVIDUALLOAN_CASE,
        Case.State.APPROVED);
    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.DISBURSE, Action.CLOSE);

    final String customerLoanLedgerIdentifier = AccountingFixture.verifyLedgerCreation(
        ledgerManager,
        AccountingFixture.CUSTOMER_LOAN_LEDGER_IDENTIFIER,
        AccountType.ASSET);

    customerLoanPrincipalIdentifier =
        AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, AccountType.ASSET);
    customerLoanInterestIdentifier =
        AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_INTEREST, AccountType.ASSET);
    customerLoanFeeIdentifier =
        AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_FEES, AccountType.ASSET);

    expectedCurrentBalance = BigDecimal.ZERO;
  }

  //Approve the case, accept a loan origination fee, and prepare to disburse the loan by earmarking the funds.
  private void step5Disburse(
      final BigDecimal amount,
      final String whichDisbursementFee,
      final BigDecimal disbursementFeeAmount) throws InterruptedException {
    logger.info("step5Disburse");
    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.DISBURSE,
        Sets.newLinkedHashSet(AccountDesignators.ENTRY, AccountDesignators.CUSTOMER_LOAN_GROUP),
        amount,
        new CostComponent(whichDisbursementFee, disbursementFeeAmount),
        new CostComponent(ChargeIdentifiers.LOAN_ORIGINATION_FEE_ID, LOAN_ORIGINATION_FEE_AMOUNT),
        new CostComponent(ChargeIdentifiers.PROCESSING_FEE_ID, PROCESSING_FEE_AMOUNT),
        new CostComponent(ChargeIdentifiers.DISBURSE_PAYMENT_ID, amount));
    checkStateTransfer(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.DISBURSE,
        LocalDateTime.now(Clock.systemUTC()),
        Collections.singletonList(assignEntryToTeller()),
        amount,
        IndividualLoanEventConstants.DISBURSE_INDIVIDUALLOAN_CASE,
        midnightToday(),
        Case.State.ACTIVE);
    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPLY_INTEREST,
        Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.WRITE_OFF, Action.CLOSE);

    final Set<Debtor> debtors = new HashSet<>();
    debtors.add(new Debtor(customerLoanPrincipalIdentifier, amount.toPlainString()));
    debtors.add(new Debtor(customerLoanFeeIdentifier, PROCESSING_FEE_AMOUNT.toPlainString()));
    debtors.add(new Debtor(customerLoanFeeIdentifier, disbursementFeeAmount.toPlainString()));
    debtors.add(new Debtor(customerLoanFeeIdentifier, LOAN_ORIGINATION_FEE_AMOUNT.toPlainString()));

    final Set<Creditor> creditors = new HashSet<>();
    creditors.add(new Creditor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, amount.toString()));
    creditors.add(new Creditor(AccountingFixture.PROCESSING_FEE_INCOME_ACCOUNT_IDENTIFIER, PROCESSING_FEE_AMOUNT.toPlainString()));
    creditors.add(new Creditor(AccountingFixture.DISBURSEMENT_FEE_INCOME_ACCOUNT_IDENTIFIER, disbursementFeeAmount.toPlainString()));
    creditors.add(new Creditor(AccountingFixture.LOAN_ORIGINATION_FEES_ACCOUNT_IDENTIFIER, LOAN_ORIGINATION_FEE_AMOUNT.toPlainString()));
    AccountingFixture.verifyTransfer(ledgerManager, debtors, creditors, product.getIdentifier(), customerCase.getIdentifier(), Action.DISBURSE);

    expectedCurrentBalance = expectedCurrentBalance.add(amount);
    nonLateFees = nonLateFees.add(disbursementFeeAmount);
  }

  private void step6CalculateInterestAndCheckForLatenessForWeek(
      final LocalDateTime referenceDate,
      final int weekNumber) throws InterruptedException {
    step6CalculateInterestAndCheckForLatenessForRangeOfDays(
        referenceDate,
        (weekNumber * 7) + 1,
        (weekNumber + 1) * 7,
        -1,
        null);
  }

  private void step6CalculateInterestAndCheckForLatenessForRangeOfDays(
      final LocalDateTime referenceDate,
      final int startInclusive,
      final int endInclusive,
      final int dayOfLateFee,
      final BigDecimal calculatedLateFee) throws InterruptedException {
    try {
      IntStream.rangeClosed(startInclusive, endInclusive)
          .mapToObj(referenceDate::plusDays)
          .forEach(day -> {
            try {
              if (day.equals(referenceDate.plusDays(dayOfLateFee))) {
                step6CalculateInterestAccrualAndCheckForLateness(day, calculatedLateFee);
              }
              else {
                step6CalculateInterestAccrualAndCheckForLateness(day, null);
              }
            } catch (InterruptedException e) {
              throw new RuntimeException(e);
            }
          });
    }
    catch (RuntimeException e) {
      final Throwable cause = e.getCause();
      if (cause != null && cause.getClass().isAssignableFrom(InterruptedException.class))
        throw (InterruptedException)e.getCause();
      else
        throw e;
    }
  }

  //Perform daily interest calculation.
  private void step6CalculateInterestAccrualAndCheckForLateness(
      final LocalDateTime forTime,
      final BigDecimal calculatedLateFee) throws InterruptedException {
    logger.info("step6CalculateInterestAccrualAndCheckForLateness");
    final String beatIdentifier = "alignment0";
    final String midnightTimeStamp = DateConverter.toIsoString(forTime);

    AccountingFixture.mockBalance(customerLoanPrincipalIdentifier, expectedCurrentBalance);

    final BigDecimal calculatedInterest = expectedCurrentBalance.multiply(Fixture.INTEREST_RATE.divide(Fixture.ACCRUAL_PERIODS, 8, BigDecimal.ROUND_HALF_EVEN))
        .setScale(MINOR_CURRENCY_UNIT_DIGITS, BigDecimal.ROUND_HALF_EVEN);


    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.APPLY_INTEREST,
        null,
        null,
        new CostComponent(ChargeIdentifiers.INTEREST_ID, calculatedInterest));

    if (calculatedLateFee != null) {
      checkCostComponentForActionCorrect(
          product.getIdentifier(),
          customerCase.getIdentifier(),
          Action.MARK_LATE,
          null,
          null,
          new CostComponent(ChargeIdentifiers.LATE_FEE_ID, calculatedLateFee));
    }
    final BeatPublish interestBeat = new BeatPublish(beatIdentifier, midnightTimeStamp);
    portfolioBeatListener.publishBeat(interestBeat);
    Assert.assertTrue(this.eventRecorder.wait(io.mifos.rhythm.spi.v1.events.EventConstants.POST_PUBLISHEDBEAT,
        new BeatPublishEvent(EventConstants.DESTINATION, beatIdentifier, midnightTimeStamp)));

    Assert.assertTrue(this.eventRecorder.wait(IndividualLoanEventConstants.CHECK_LATE_INDIVIDUALLOAN_CASE,
        new IndividualLoanCommandEvent(product.getIdentifier(), customerCase.getIdentifier(), midnightTimeStamp)));

    Assert.assertTrue(eventRecorder.wait(IndividualLoanEventConstants.APPLY_INTEREST_INDIVIDUALLOAN_CASE,
        new IndividualLoanCommandEvent(product.getIdentifier(), customerCase.getIdentifier(), midnightTimeStamp)));


    final Case customerCaseAfterStateChange = portfolioManager.getCase(product.getIdentifier(), customerCase.getIdentifier());
    Assert.assertEquals(customerCaseAfterStateChange.getCurrentState(), Case.State.ACTIVE.name());


    interestAccrued = interestAccrued.add(calculatedInterest);

    final Set<Debtor> debtors = new HashSet<>();
    debtors.add(new Debtor(
        customerLoanInterestIdentifier,
        calculatedInterest.toPlainString()));

    final Set<Creditor> creditors = new HashSet<>();
    creditors.add(new Creditor(
        AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER,
        calculatedInterest.toPlainString()));
    AccountingFixture.verifyTransfer(ledgerManager, debtors, creditors, product.getIdentifier(), customerCase.getIdentifier(), Action.APPLY_INTEREST);

    expectedCurrentBalance = expectedCurrentBalance.add(calculatedInterest);
  }

  private void step7PaybackPartialAmount(
      final BigDecimal amount,
      final LocalDateTime referenceDate,
      final int dayNumber,
      final BigDecimal lateFee) throws InterruptedException {
    logger.info("step7PaybackPartialAmount '{}'", amount);

    final BigDecimal principal = amount.subtract(interestAccrued).subtract(lateFee).subtract(nonLateFees);
    final BigDecimal allFees = lateFee.add(nonLateFees);
    AccountingFixture.mockBalance(customerLoanPrincipalIdentifier, principal);
    AccountingFixture.mockBalance(customerLoanFeeIdentifier, allFees);
    AccountingFixture.mockBalance(customerLoanInterestIdentifier, interestAccrued);
    AccountingFixture.mockBalance(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued);
    AccountingFixture.mockBalance(AccountingFixture.LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER, lateFee);

    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.ACCEPT_PAYMENT,
        new HashSet<>(Arrays.asList(AccountDesignators.ENTRY, AccountDesignators.CUSTOMER_LOAN_GROUP, AccountDesignators.LOAN_FUNDS_SOURCE)),
        amount,
        new CostComponent(ChargeIdentifiers.REPAY_PRINCIPAL_ID, principal),
        new CostComponent(ChargeIdentifiers.REPAY_INTEREST_ID, interestAccrued),
        new CostComponent(ChargeIdentifiers.REPAY_FEES_ID, allFees),
        new CostComponent(ChargeIdentifiers.INTEREST_ID, interestAccrued),
        new CostComponent(ChargeIdentifiers.LATE_FEE_ID, lateFee));
    checkStateTransfer(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.ACCEPT_PAYMENT,
        referenceDate.plusDays(dayNumber),
        Collections.singletonList(assignEntryToTeller()),
        amount,
        IndividualLoanEventConstants.ACCEPT_PAYMENT_INDIVIDUALLOAN_CASE,
        midnightToday(),
        Case.State.ACTIVE); //Close has to be done explicitly.
    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPLY_INTEREST,
        Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.WRITE_OFF, Action.CLOSE);

    final Set<Debtor> debtors = new HashSet<>();
    debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, principal.toPlainString()));
    if (interestAccrued.compareTo(BigDecimal.ZERO) != 0) {
      debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
      debtors.add(new Debtor(AccountingFixture.LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
    }
    if (allFees.compareTo(BigDecimal.ZERO) != 0) {
      debtors.add(new Debtor(AccountingFixture.TELLER_ONE_ACCOUNT_IDENTIFIER, allFees.toPlainString()));
    }
    if (lateFee.compareTo(BigDecimal.ZERO) != 0) {
      debtors.add(new Debtor(AccountingFixture.LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER, lateFee.toPlainString()));
    }

    final Set<Creditor> creditors = new HashSet<>();
    creditors.add(new Creditor(customerLoanPrincipalIdentifier, principal.toPlainString()));
    if (interestAccrued.compareTo(BigDecimal.ZERO) != 0) {
      creditors.add(new Creditor(customerLoanInterestIdentifier, interestAccrued.toPlainString()));
      creditors.add(new Creditor(AccountingFixture.CONSUMER_LOAN_INTEREST_ACCOUNT_IDENTIFIER, interestAccrued.toPlainString()));
    }
    if (allFees.compareTo(BigDecimal.ZERO) != 0) {
      creditors.add(new Creditor(customerLoanFeeIdentifier, allFees.toPlainString()));
    }
    if (lateFee.compareTo(BigDecimal.ZERO) != 0) {
      creditors.add(new Creditor(AccountingFixture.LATE_FEE_INCOME_ACCOUNT_IDENTIFIER, lateFee.toPlainString()));
    }

    AccountingFixture.verifyTransfer(ledgerManager, debtors, creditors, product.getIdentifier(), customerCase.getIdentifier(), Action.ACCEPT_PAYMENT);

    expectedCurrentBalance = expectedCurrentBalance.subtract(amount).add(lateFee);
    interestAccrued = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
    nonLateFees = BigDecimal.ZERO.setScale(MINOR_CURRENCY_UNIT_DIGITS, RoundingMode.HALF_EVEN);
  }

  private void step8Close() throws InterruptedException {
    logger.info("step8Close");

    AccountingFixture.mockBalance(customerLoanPrincipalIdentifier, expectedCurrentBalance);

    checkCostComponentForActionCorrect(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.CLOSE,
        null,
        null);
    checkStateTransfer(
        product.getIdentifier(),
        customerCase.getIdentifier(),
        Action.CLOSE,
        Collections.singletonList(assignEntryToTeller()),
        IndividualLoanEventConstants.CLOSE_INDIVIDUALLOAN_CASE,
        Case.State.CLOSED); //Close has to be done explicitly.

    checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier());
  }
}