← back to StudentLoanTracker

src/lib/calculators/comparison.ts

77 lines

/**
 * Plan Comparison Engine
 *
 * Runs all IDR calculators and produces a unified comparison
 * with recommendations for lowest monthly, lowest total cost,
 * and fastest payoff.
 */

import { LoanInputs, PlanResult, ComparisonResult } from './types';
import { calculateSAVE } from './save-calculator';
import { calculateIBR } from './ibr-calculator';
import { calculatePAYE } from './paye-calculator';
import { calculateICR } from './icr-calculator';

/**
 * Calculate the 10-year Standard repayment plan for baseline comparison.
 */
function calculateStandard(inputs: LoanInputs): PlanResult {
  const { totalBalance, weightedRate } = inputs;
  const monthlyRate = weightedRate / 12;
  const months = 120;

  const monthlyPayment =
    monthlyRate > 0
      ? (totalBalance * monthlyRate) / (1 - Math.pow(1 + monthlyRate, -months))
      : totalBalance / months;

  const totalPaid = monthlyPayment * months;

  return {
    planName: 'Standard (10-Year)',
    monthlyPayment: Math.round(monthlyPayment * 100) / 100,
    totalPaid: Math.round(totalPaid * 100) / 100,
    totalInterest: Math.round((totalPaid - totalBalance) * 100) / 100,
    forgivenessAmount: 0,
    forgivenessMonths: 0,
    repaymentMonths: months,
    discretionaryIncome: 0,
    povertyGuideline: 0,
  };
}

/**
 * Compare all available repayment plans.
 */
export function compareAllPlans(inputs: LoanInputs): ComparisonResult {
  const plans: PlanResult[] = [
    calculateStandard(inputs),
    calculateSAVE(inputs),
    calculateIBR(inputs, true),   // New IBR
    calculateIBR(inputs, false),  // Old IBR
    calculatePAYE(inputs),
    calculateICR(inputs),
  ];

  // Find recommendations
  const lowestMonthly = plans.reduce((min, p) =>
    p.monthlyPayment < min.monthlyPayment ? p : min
  );

  const lowestTotal = plans.reduce((min, p) =>
    p.totalPaid < min.totalPaid ? p : min
  );

  const fastestPayoff = plans.reduce((min, p) =>
    p.repaymentMonths < min.repaymentMonths ? p : min
  );

  return {
    inputs,
    plans,
    recommended: lowestTotal.planName,
    lowestMonthly: lowestMonthly.planName,
    fastestPayoff: fastestPayoff.planName,
  };
}