/*
 * 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.individuallending.internal.service;

import io.mifos.individuallending.IndividualLendingPatternFactory;
import io.mifos.individuallending.api.v1.domain.caseinstance.CaseParameters;
import io.mifos.individuallending.api.v1.domain.caseinstance.ChargeName;
import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPayment;
import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPaymentPage;
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.workflow.Action;
import io.mifos.portfolio.api.v1.domain.*;
import io.mifos.portfolio.service.internal.service.ChargeDefinitionService;
import io.mifos.portfolio.service.internal.service.ProductService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.Mockito;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.mifos.individuallending.api.v1.domain.product.ChargeIdentifiers.*;

/**
 * @author Myrle Krantz
 */
@RunWith(Parameterized.class)
public class IndividualLoanServiceTest {

  private static class ActionDatePair {
    final Action action;
    final LocalDate localDate;

    ActionDatePair(final Action action, final LocalDate localDate) {
      this.action = action;
      this.localDate = localDate;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      ActionDatePair that = (ActionDatePair) o;
      return action == that.action &&
              Objects.equals(localDate, that.localDate);
    }

    @Override
    public int hashCode() {
      return Objects.hash(action, localDate);
    }

    @Override
    public String toString() {
      return "ActionDatePair{" +
              "action=" + action +
              ", localDate=" + localDate +
              '}';
    }
  }


  private static class TestCase {
    private final String description;
    private String productIdentifier = "blah";
    private int minorCurrencyUnitDigits = 2;
    private CaseParameters caseParameters;
    private LocalDate initialDisbursementDate;
    private Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAction;
    private Set<String> expectedChargeIdentifiers = new HashSet<>(Arrays.asList(ChargeIdentifiers.INTEREST_ID, ChargeIdentifiers.REPAYMENT_ID));
    private Map<ActionDatePair, List<ChargeDefinition>> chargeDefinitionsForActions = new HashMap<>();
    //This is an abuse of the ChargeInstance since everywhere else it's intended to contain account identifiers and not
    //account designators.  Don't copy the code around charge instances in this test without thinking about what you're
    //doing carefully first.

    TestCase(final String description) {
      this.description = description;
    }

    TestCase minorCurrencyUnitDigits(final int newVal) {
      this.minorCurrencyUnitDigits = newVal;
      return this;
    }

    TestCase caseParameters(final CaseParameters newVal) {
      this.caseParameters = newVal;
      return this;
    }

    TestCase initialDisbursementDate(final LocalDate newVal) {
      this.initialDisbursementDate = newVal;
      return this;
    }

    TestCase chargeDefinitionsMappedByAction(final Map<String, List<ChargeDefinition>> newVal) {
      this.chargeDefinitionsMappedByAction = newVal;
      return this;
    }

    TestCase expectedChargeIdentifiers(final Set<String> newVal) {
      this.expectedChargeIdentifiers = newVal;
      return this;
    }

    TestCase expectAdditionalChargeIdentifier(final String newVal) {
      this.expectedChargeIdentifiers.add(newVal);
      return this;
    }

    TestCase expectChargeInstancesForActionDatePair(final Action action,
                                                    final LocalDate forDate,
                                                    final List<ChargeDefinition> chargeDefinitions) {
      this.chargeDefinitionsForActions.put(new ActionDatePair(action, forDate), chargeDefinitions);
      return this;
    }

    @Override
    public String toString() {
      return "TestCase{" +
              "description='" + description + '\'' +
              '}';
    }
  }

  @Parameterized.Parameters
  public static Collection testCases() {
    final Collection<TestCase> ret = new ArrayList<>();
    ret.add(simpleCase());
    ret.add(yearLoanTestCase());
    ret.add(chargeDefaultsCase());
    return ret;
  }

  private final TestCase testCase;
  private final IndividualLoanService testSubject;
  private final Product product;


  private static TestCase simpleCase()
  {
    final LocalDate initialDisbursementDate = LocalDate.of(2017, 1, 5);
    //final Period firstRepaymentPeriod = new Period(initialDisbursementDate, 1);
    final CaseParameters caseParameters = Fixture.getTestCaseParameters();
    caseParameters.setTermRange(new TermRange(ChronoUnit.WEEKS, 3));
    caseParameters.setPaymentCycle(new PaymentCycle(ChronoUnit.WEEKS, 1, 0, null, null));

    //I know: this is cheating in a unit test.  But I really didn't want to put this data together by hand.
    final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAction = constructCharges(0.01);
    final ChargeDefinition processingFeeCharge = getFixedSingleChargeDefinition(10.0, Action.OPEN, PROCESSING_FEE_ID, AccountDesignators.PROCESSING_FEE_INCOME);
    chargeDefinitionsMappedByAction.put(Action.OPEN.name(), Collections.singletonList(processingFeeCharge));
    final ChargeDefinition loanOriginationFeeCharge = getFixedSingleChargeDefinition(100.0, Action.APPROVE, LOAN_ORIGINATION_FEE_ID, AccountDesignators.ORIGINATION_FEE_INCOME);
    final List<ChargeDefinition> existingApprovalCharges = chargeDefinitionsMappedByAction.get(Action.APPROVE.name());
    final List<ChargeDefinition> approvalChargesWithLoanOriginationFeeReplaced = existingApprovalCharges.stream().map(x -> {
      if (x.getIdentifier().equals(LOAN_ORIGINATION_FEE_ID))
        return loanOriginationFeeCharge;
      else
        return x;
    }).collect(Collectors.toList());
    chargeDefinitionsMappedByAction.put(Action.APPROVE.name(), approvalChargesWithLoanOriginationFeeReplaced);

    return new TestCase("simpleCase")
            .minorCurrencyUnitDigits(2)
            .caseParameters(caseParameters)
            .initialDisbursementDate(initialDisbursementDate)
            .chargeDefinitionsMappedByAction(chargeDefinitionsMappedByAction)
            .expectAdditionalChargeIdentifier(PROCESSING_FEE_ID)
            .expectAdditionalChargeIdentifier(LOAN_FUNDS_ALLOCATION_ID)
            .expectAdditionalChargeIdentifier(LOAN_ORIGINATION_FEE_ID)
            .expectChargeInstancesForActionDatePair(Action.OPEN, initialDisbursementDate, Collections.singletonList(processingFeeCharge))
            .expectChargeInstancesForActionDatePair(Action.APPROVE, initialDisbursementDate,
                Collections.singletonList(loanOriginationFeeCharge));
  }

  private static TestCase yearLoanTestCase()
  {
    final LocalDate initialDisbursementDate = LocalDate.of(2017, 1, 1);
    //final Period firstRepaymentPeriod = new Period(initialDisbursementDate, 1);
    final CaseParameters caseParameters = Fixture.getTestCaseParameters();
    caseParameters.setTermRange(new TermRange(ChronoUnit.YEARS, 1));
    caseParameters.setPaymentCycle(new PaymentCycle(ChronoUnit.MONTHS, 1, 0, null, null));
    caseParameters.setMaximumBalance(BigDecimal.valueOf(200000));

    final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAction = constructCharges(0.10);

    return new TestCase("yearLoanTestCase")
            .minorCurrencyUnitDigits(3)
            .caseParameters(caseParameters)
            .initialDisbursementDate(initialDisbursementDate)
            .chargeDefinitionsMappedByAction(chargeDefinitionsMappedByAction);
  }

  private static TestCase chargeDefaultsCase()
  {
    final LocalDate initialDisbursementDate = LocalDate.of(2017, 2, 6);
    final CaseParameters caseParameters = Fixture.getTestCaseParameters();
    caseParameters.setTermRange(new TermRange(ChronoUnit.MONTHS, 6));
    caseParameters.setPaymentCycle(new PaymentCycle(ChronoUnit.WEEKS, 1, 1, 0, 0));
    caseParameters.setMaximumBalance(BigDecimal.valueOf(2000));

    final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAction = constructCharges(0.05);

    return new TestCase("chargeDefaultsCase")
            .minorCurrencyUnitDigits(2)
            .caseParameters(caseParameters)
            .initialDisbursementDate(initialDisbursementDate)
            .chargeDefinitionsMappedByAction(chargeDefinitionsMappedByAction)
            .expectedChargeIdentifiers(new HashSet<>(Arrays.asList(PROCESSING_FEE_ID, LOAN_FUNDS_ALLOCATION_ID, RETURN_DISBURSEMENT_ID, LOAN_ORIGINATION_FEE_ID, INTEREST_ID, DISBURSEMENT_FEE_ID, REPAYMENT_ID)));
  }

  private static Map<String, List<ChargeDefinition>> constructCharges(final double interestRate) {
    final List<ChargeDefinition> defaultLoanCharges = IndividualLendingPatternFactory.defaultIndividualLoanCharges();

    final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAction = defaultLoanCharges.stream()
            .collect(Collectors.groupingBy(ChargeDefinition::getChargeAction,
                    Collectors.mapping(x -> x, Collectors.toList())));

    chargeDefinitionsMappedByAction.put(Action.APPLY_INTEREST.name(), getInterestChargeDefinition(interestRate, ChronoUnit.YEARS));
    return chargeDefinitionsMappedByAction;
  }

  private static List<ChargeDefinition> getInterestChargeDefinition(final double amount, final ChronoUnit forCycleSizeUnit) {
    final ChargeDefinition ret = new ChargeDefinition();
    ret.setAmount(BigDecimal.valueOf(amount));
    ret.setIdentifier(ChargeIdentifiers.INTEREST_ID);
    ret.setAccrueAction(Action.APPLY_INTEREST.name());
    ret.setChargeAction(Action.ACCEPT_PAYMENT.name());
    ret.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
    ret.setProportionalTo(ChargeIdentifiers.RUNNING_BALANCE_DESIGNATOR);
    ret.setFromAccountDesignator(AccountDesignators.CUSTOMER_LOAN);
    ret.setAccrualAccountDesignator(AccountDesignators.INTEREST_ACCRUAL);
    ret.setToAccountDesignator(AccountDesignators.INTEREST_INCOME);
    ret.setForCycleSizeUnit(forCycleSizeUnit);
    return Collections.singletonList(ret);
  }

  private static ChargeDefinition getFixedSingleChargeDefinition(
          final double amount,
          final Action action,
          final String chargeIdentifier,
          final String feeAccountDesignator) {
    final ChargeDefinition ret = new ChargeDefinition();
    ret.setAmount(BigDecimal.valueOf(amount));
    ret.setIdentifier(chargeIdentifier);
    ret.setAccrueAction(null);
    ret.setChargeAction(action.name());
    ret.setChargeMethod(ChargeDefinition.ChargeMethod.FIXED);
    ret.setProportionalTo(null);
    ret.setFromAccountDesignator(AccountDesignators.ENTRY);
    ret.setToAccountDesignator(feeAccountDesignator);
    ret.setForCycleSizeUnit(null);
    return ret;
  }

  private static ChargeDefinition getProportionalSingleChargeDefinition(
          final double amount,
          final Action action,
          final String chargeIdentifier,
          final String fromAccountDesignator,
          final String toAccountDesignator) {
    final ChargeDefinition ret = new ChargeDefinition();
    ret.setAmount(BigDecimal.valueOf(amount));
    ret.setIdentifier(chargeIdentifier);
    ret.setAccrueAction(null);
    ret.setChargeAction(action.name());
    ret.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
    ret.setProportionalTo(ChargeIdentifiers.MAXIMUM_BALANCE_DESIGNATOR);
    ret.setFromAccountDesignator(fromAccountDesignator);
    ret.setToAccountDesignator(toAccountDesignator);
    ret.setForCycleSizeUnit(null);
    return ret;
  }

  public IndividualLoanServiceTest(final TestCase testCase)
  {
    this.testCase = testCase;

    final ProductService productServiceMock = Mockito.mock(ProductService.class);
    final ChargeDefinitionService chargeDefinitionServiceMock = Mockito.mock(ChargeDefinitionService.class);
    product = new Product();
    product.setMinorCurrencyUnitDigits(testCase.minorCurrencyUnitDigits);
    Mockito.doReturn(Optional.of(product)).when(productServiceMock).findByIdentifier(testCase.productIdentifier);
    Mockito.doReturn(testCase.chargeDefinitionsMappedByAction).when(chargeDefinitionServiceMock).getChargeDefinitionsMappedByChargeAction(testCase.productIdentifier);

    testSubject = new IndividualLoanService(productServiceMock, chargeDefinitionServiceMock, new PeriodChargeCalculator());
  }

  @Test
  public void getPlannedPayments() throws Exception {
    final PlannedPaymentPage firstPage = testSubject.getPlannedPaymentsPage(testCase.productIdentifier,
            testCase.caseParameters,
            0,
            20,
            testCase.initialDisbursementDate);

    final List<PlannedPayment> allPlannedPayments =
            Stream.iterate(0, x -> x + 1).limit(firstPage.getTotalPages())
            .map(x -> testSubject.getPlannedPaymentsPage(testCase.productIdentifier,
                    testCase.caseParameters, x, 20, testCase.initialDisbursementDate))
            .flatMap(x -> x.getElements().stream())
            .collect(Collectors.toList());

    //Remaining principal should correspond with the other cost components.
    Stream.iterate(0, x -> x+1).limit(allPlannedPayments.size()-2).forEach(x ->
            {
              final BigDecimal costComponentSum = allPlannedPayments.get(x+1).getCostComponents().stream()
                      .map(CostComponent::getAmount)
                      .reduce(BigDecimal::add)
                      .orElse(BigDecimal.ZERO)
                      .negate();
              final BigDecimal principalDifference = allPlannedPayments.get(x).getRemainingPrincipal().subtract(allPlannedPayments.get(x + 1).getRemainingPrincipal());
              Assert.assertEquals(costComponentSum, principalDifference);
              Assert.assertNotEquals("Remaining principle should always be positive or zero.",
                      allPlannedPayments.get(x).getRemainingPrincipal().signum(), -1);
            }
    );

    //All entries should have the correct scale.
    allPlannedPayments.forEach(x -> {
      x.getCostComponents().forEach(y -> Assert.assertEquals(product.getMinorCurrencyUnitDigits(), y.getAmount().scale()));
      Assert.assertEquals(product.getMinorCurrencyUnitDigits(), x.getRemainingPrincipal().scale());
    });

    //All customer payments should be within one percent of each other.
    final Set<BigDecimal> customerRepayments = allPlannedPayments.stream()
        .map(this::getCustomerRepayment)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .collect(Collectors.toSet());
    final Optional<BigDecimal> maxPayment = customerRepayments.stream().max(BigDecimal::compareTo);
    final Optional<BigDecimal> minPayment = customerRepayments.stream().min(BigDecimal::compareTo);
    Assert.assertTrue(maxPayment.isPresent());
    Assert.assertTrue(minPayment.isPresent());
    final double percentDifference = percentDifference(maxPayment.get(), minPayment.get());
    Assert.assertTrue("Percent difference = " + percentDifference, percentDifference < 0.01);

    //Final balance should be zero.
    Assert.assertEquals(BigDecimal.ZERO.setScale(testCase.minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN),
            allPlannedPayments.get(allPlannedPayments.size()-1).getRemainingPrincipal());

    //All charge identifers should be associated with a name on the returned page.
    final Set<String> resultChargeIdentifiers = firstPage.getChargeNames().stream()
            .map(ChargeName::getIdentifier)
            .collect(Collectors.toSet());

    Assert.assertEquals(testCase.expectedChargeIdentifiers, resultChargeIdentifiers);
  }

  @Test
  public void getScheduledCharges() {
    final List<ScheduledAction> scheduledActions = ScheduledActionHelpers.getHypotheticalScheduledActions(testCase.initialDisbursementDate, testCase.caseParameters);
    final List<ScheduledCharge> scheduledCharges = testSubject.getScheduledCharges(testCase.productIdentifier,
        scheduledActions);

    final List<LocalDate> interestCalculationDates = scheduledCharges.stream()
        .filter(scheduledCharge -> scheduledCharge.getScheduledAction().action == Action.APPLY_INTEREST)
        .map(scheduledCharge -> scheduledCharge.getScheduledAction().when)
        .collect(Collectors.toList());

    final List<LocalDate> allTheDaysAfterTheInitialDisbursementDate
        = Stream.iterate(testCase.initialDisbursementDate.plusDays(1), interestDay -> interestDay.plusDays(1))
        .limit(interestCalculationDates.size())
        .collect(Collectors.toList());

    Assert.assertEquals(interestCalculationDates, allTheDaysAfterTheInitialDisbursementDate);

    final List<LocalDate> acceptPaymentDates = scheduledCharges.stream()
        .filter(scheduledCharge -> scheduledCharge.getScheduledAction().action == Action.ACCEPT_PAYMENT)
        .map(scheduledCharge -> scheduledCharge.getScheduledAction().when)
        .collect(Collectors.toList());
    final long expectedAcceptPayments = scheduledActions.stream()
        .filter(x -> x.action == Action.ACCEPT_PAYMENT).count();
    final List<ChargeDefinition> chargeDefinitionsMappedToAcceptPayment = testCase.chargeDefinitionsMappedByAction.get(Action.ACCEPT_PAYMENT.name());
    final int numberOfChangeDefinitionsMappedToAcceptPayment = chargeDefinitionsMappedToAcceptPayment == null ? 0 : chargeDefinitionsMappedToAcceptPayment.size();
    Assert.assertEquals("check for correct number of scheduled charges for accept payment",
        expectedAcceptPayments*numberOfChangeDefinitionsMappedToAcceptPayment,
        acceptPaymentDates.size());

    final Map<ActionDatePair, Set<ChargeDefinition>> searchableScheduledCharges = scheduledCharges.stream()
        .collect(
            Collectors.groupingBy(scheduledCharge ->
                new ActionDatePair(scheduledCharge.getScheduledAction().action, scheduledCharge.getScheduledAction().when),
                Collectors.mapping(ScheduledCharge::getChargeDefinition, Collectors.toSet())));

    testCase.chargeDefinitionsForActions.forEach((key, value) -> value.forEach(x -> Assert.assertTrue(searchableScheduledCharges.get(key).contains(x))));
  }

  private double percentDifference(final BigDecimal maxPayment, final BigDecimal minPayment) {
    final BigDecimal difference = maxPayment.subtract(minPayment);
    final BigDecimal percentDifference = difference.divide(maxPayment, 4, BigDecimal.ROUND_UP);
    return percentDifference.doubleValue();
  }

  private Optional<BigDecimal> getCustomerRepayment(final PlannedPayment plannedPayment) {
    final Optional<CostComponent> ret = plannedPayment.getCostComponents().stream()
            .filter(y -> y.getChargeIdentifier().equals(ChargeIdentifiers.REPAYMENT_ID))
            .findAny();

    return ret.map(x -> x.getAmount().abs());
  }
}
