"""
Core loan calculation utilities.
Mirrors the logic in static/js/calculator.js for server-side validation.
"""


def calculate_repayments(principal: float, annual_rate: float,
                          term_months: int, frequency: str = 'monthly') -> dict:
    periods_per_year = {'weekly': 52, 'fortnightly': 26, 'monthly': 12}.get(frequency, 12)
    total_periods = round(term_months / 12 * periods_per_year)
    period_rate = (annual_rate / 100) / periods_per_year

    if period_rate == 0 or total_periods == 0:
        payment = principal / total_periods if total_periods else 0
    else:
        payment = principal * (period_rate * (1 + period_rate) ** total_periods) \
                  / ((1 + period_rate) ** total_periods - 1)

    total_repayable = payment * total_periods
    total_interest = total_repayable - principal
    comparison_rate = _nccp_comparison_rate(annual_rate)

    schedule = generate_amortisation(principal, annual_rate, term_months, frequency, max_rows=12)

    return {
        'payment': round(payment, 2),
        'total_repayable': round(total_repayable, 2),
        'total_interest': round(total_interest, 2),
        'annual_rate': annual_rate,
        'comparison_rate': round(comparison_rate, 2),
        'frequency': frequency,
        'term_months': term_months,
        'principal': principal,
        'schedule': schedule,
    }


def generate_amortisation(principal: float, annual_rate: float,
                           term_months: int, frequency: str = 'monthly',
                           max_rows: int = 12) -> list:
    periods_per_year = {'weekly': 52, 'fortnightly': 26, 'monthly': 12}.get(frequency, 12)
    total_periods = round(term_months / 12 * periods_per_year)
    period_rate = (annual_rate / 100) / periods_per_year

    if period_rate == 0 or total_periods == 0:
        payment = principal / total_periods if total_periods else 0
    else:
        payment = principal * (period_rate * (1 + period_rate) ** total_periods) \
                  / ((1 + period_rate) ** total_periods - 1)

    balance = principal
    rows = []
    for i in range(1, min(total_periods + 1, max_rows + 1)):
        interest_portion = balance * period_rate
        principal_portion = payment - interest_portion
        balance -= principal_portion
        rows.append({
            'period': i,
            'payment': round(payment, 2),
            'principal': round(principal_portion, 2),
            'interest': round(interest_portion, 2),
            'balance': round(max(balance, 0), 2),
        })
    return rows


def _nccp_comparison_rate(annual_rate: float, fees: float = 0) -> float:
    """
    NCCP Act comparison rate based on $150,000 over 60 months.
    Simplified: includes fees annualised. In production use an actuary-grade formula.
    """
    principal = 150_000
    term_months = 60
    period_rate = (annual_rate / 100) / 12
    if period_rate == 0:
        return annual_rate
    payment = principal * (period_rate * (1 + period_rate) ** term_months) \
              / ((1 + period_rate) ** term_months - 1)
    payment += fees / term_months
    # Back-solve for comparison rate (Newton's method approximation)
    # For simplicity, use annual_rate + fee uplift
    total_repayable = payment * term_months
    total_interest = total_repayable - principal
    approx_rate = (total_interest / principal) / (term_months / 12) * 100
    return round(approx_rate, 2)
