package com.sunxung.factoring.component.util;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName:EqualPrincipalInterestUtil_new
 * @Description:等额本息工具类：也称定期付息，即借款人每期按照相等的金额偿还贷款的利息，其中每期贷款的利息按期初剩余贷款本金计算并逐期结清。<br/> （把按揭贷款的本金总额与利息总额相加，然后平均分摊到还款期限的每个月中。作为还款人，每个月还给银行固定金额，但每月还款额中的本金比重逐月递增、利息比重逐月递减。）
 * @Author:wanxiangZhou
 * @Email:303526821@qq.com
 * @Date:2017年3月28日 上午11:54:20
 */
public class EqualPrincipalInterestUtil_new {

    /**
     * 每期偿还本金和利息，公式：每期偿还本息=〔贷款本金×期利率×(1＋期利率)＾还款期数〕÷〔(1＋期利率)＾还款期数-1〕
     *
     * @param invest   总借款额（贷款本金）
     * @param yearRate 年利率
     * @param period   还款总期数
     * @param base     月基数
     * @return
     */
    public static BigDecimal getPerPeriodPrincipalInterest(BigDecimal invest, double periodRate, int period, int base) {
//        double periodRate = yearRate / base;
        BigDecimal periodIncome = invest.multiply(new BigDecimal(periodRate * Math.pow(1 + periodRate, period)))
                .divide(new BigDecimal(Math.pow(1 + periodRate, period) - 1), 2, BigDecimal.ROUND_HALF_UP);
        return periodIncome;
    }

    /**
     * 每期偿还利息，公式：每期偿还利息=贷款本金×期利率×〔(1+期利率)^还款期数-(1+期利率)^(还款期序号-1)〕÷〔(1+期利率)^还款期数-1〕
     *
     * @param invest     总借款额（贷款本金）
     * @param yearRate   年利率
     * @param totalmonth 还款总期数
     * @param base       月基数
     * @return
     */
    public static Map<Integer, BigDecimal> getPerPeriodInterest(BigDecimal invest, double yearRate, int period,
                                                                double base) {
        Map<Integer, BigDecimal> map = new HashMap<Integer, BigDecimal>();
        double periodRate = yearRate / base;
        BigDecimal periodInterest;
        for (int i = 1; i < period + 1; i++) {
            BigDecimal multiply = invest.multiply(new BigDecimal(periodRate));
            BigDecimal sub = new BigDecimal(Math.pow(1 + periodRate, period))
                    .subtract(new BigDecimal(Math.pow(1 + periodRate, i - 1)));
            periodInterest = multiply.multiply(sub).divide(new BigDecimal(Math.pow(1 + periodRate, period) - 1), 6,
                    BigDecimal.ROUND_DOWN);
            periodInterest = periodInterest.setScale(2, BigDecimal.ROUND_HALF_UP);
            map.put(i, periodInterest);
        }
        return map;
    }

    /**
     * 等额本息计算获取还款方式为等额本息的每期偿还本金
     *
     * @param invest   总借款额（贷款本金）
     * @param yearRate 年利率
     * @param month    还款总期数
     * @param base     月基数
     * @return 每期偿还本金
     */
    public static Map<Integer, BigDecimal> getPerPeriodPrincipal(BigDecimal invest, double yearRate, int period,
                                                                 double base) {
        double periodRate = yearRate / base;
        BigDecimal monthIncome = invest.multiply(new BigDecimal(periodRate * Math.pow(1 + periodRate, period)))
                .divide(new BigDecimal(Math.pow(1 + periodRate, period) - 1), 2, BigDecimal.ROUND_HALF_UP);
        Map<Integer, BigDecimal> mapInterest = getPerPeriodInterest(invest, yearRate, period, base);
        Map<Integer, BigDecimal> mapPrincipal = new HashMap<Integer, BigDecimal>();
        for (Map.Entry<Integer, BigDecimal> entry : mapInterest.entrySet()) {
            mapPrincipal.put(entry.getKey(), monthIncome.subtract(entry.getValue()));
        }
        return mapPrincipal;
    }

    /**
     * 等额本息计算获取还款方式为等额本息的总利息
     *
     * @param invest   总借款额（贷款本金）
     * @param yearRate 年利率
     * @param month    还款总期数
     * @param base     月基数
     * @return 总利息
     */
    public static BigDecimal getInterestCount(BigDecimal invest, double yearRate, int period, int base) {
        BigDecimal count = new BigDecimal(0);
        Map<Integer, BigDecimal> mapInterest = getPerPeriodInterest(invest, yearRate, period, base);
        for (Map.Entry<Integer, BigDecimal> entry : mapInterest.entrySet()) {
            count = count.add(entry.getValue());
        }
        return count;
    }

    /**
     * 应还本息总和
     *
     * @param invest   总借款额（贷款本金）
     * @param yearRate 年利率
     * @param month    还款总月数
     * @param base     月基数
     * @return 应还本息总和
     */
    public static BigDecimal getPrincipalInterestCount(BigDecimal invest, double yearRate, int period, int base) {
        double periodRate = yearRate / base;
        BigDecimal perMonthInterest = invest.multiply(new BigDecimal(periodRate * Math.pow(1 + periodRate, period)))
                .divide(new BigDecimal(Math.pow(1 + periodRate, period) - 1), 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal count = perMonthInterest.multiply(new BigDecimal(period));
        count = count.setScale(2, BigDecimal.ROUND_HALF_UP);
        return count;
    }

    public static void main(String[] args) {
//        BigDecimal invest = new BigDecimal(1000000); // 本金
//        int month = 42;
//        int base = 7;
//        double yearRate = 0.07; // 年利率
//        double periodRate = 0.07 / 12 * 7 ;
//        BigDecimal perMonthPrincipalInterest = getPerPeriodPrincipalInterest(invest, periodRate, 6, base);
//        System.out.println("等额本息---每月还款本息：" + perMonthPrincipalInterest);
//        Map<Integer, BigDecimal> mapInterest = getPerPeriodInterest(invest, yearRate, month, base);
//        System.out.println("等额本息---每月还款利息：" + mapInterest);
//        Map<Integer, BigDecimal> mapPrincipal = getPerPeriodPrincipal(invest, yearRate, month, base);
//        System.out.println("等额本息---每月还款本金：" + mapPrincipal);
//        BigDecimal count = getInterestCount(invest, yearRate, month, base);
//        System.out.println("等额本息---总利息：" + count);
//        BigDecimal principalInterestCount = getPrincipalInterestCount(invest, yearRate, month, base);
//        System.out.println("等额本息---应还本息总和：" + principalInterestCount);
//        System.out.println("等额本息---应还本息总和：" + invest.add(count));
    }
}
