<?php

namespace App\Services;

use App\Models\Loan;
use App\Models\LoanSchedule;
use Carbon\Carbon;

class LoanService
{
    /**
     * Generate a reducing-balance equal installment schedule for the loan.
     *
     * @return \Illuminate\Support\Collection<int, LoanSchedule>
     */
    public function generateAmortizationSchedule(Loan $loan): \Illuminate\Support\Collection
    {
        $loan->schedules()->delete();

        $principal = (float) $loan->principal;
        $tenorMonths = (int) $loan->tenor_months;
        $monthlyRate = ((float) $loan->interest_rate / 100) / 12;

        if ($tenorMonths <= 0 || $principal <= 0) {
            return collect();
        }

        if ($monthlyRate <= 0) {
            $equalPrincipal = round($principal / $tenorMonths, 2);
            $remaining = $principal;
            $schedules = collect();

            for ($i = 1; $i <= $tenorMonths; $i++) {
                $principalDue = $i === $tenorMonths ? round($remaining, 2) : $equalPrincipal;
                $remaining -= $principalDue;

                $schedules->push($loan->schedules()->create([
                    'installment_no' => $i,
                    'due_date' => Carbon::parse($loan->application_date)->addMonths($i),
                    'principal_due' => $principalDue,
                    'interest_due' => 0,
                    'fees_due' => 0,
                    'total_due' => $principalDue,
                    'status' => 'pending',
                ]));
            }

            return $schedules;
        }

        $emi = $principal * ($monthlyRate * pow(1 + $monthlyRate, $tenorMonths))
            / (pow(1 + $monthlyRate, $tenorMonths) - 1);

        $balance = $principal;
        $schedules = collect();
        $startDate = Carbon::parse($loan->application_date);

        for ($i = 1; $i <= $tenorMonths; $i++) {
            $interestDue = round($balance * $monthlyRate, 2);
            $principalDue = round($emi - $interestDue, 2);

            if ($i === $tenorMonths) {
                $principalDue = round($balance, 2);
                $interestDue = round($emi - $principalDue, 2);
            }

            $totalDue = round($principalDue + $interestDue, 2);
            $balance = round($balance - $principalDue, 2);

            $schedules->push($loan->schedules()->create([
                'installment_no' => $i,
                'due_date' => $startDate->copy()->addMonths($i),
                'principal_due' => $principalDue,
                'interest_due' => $interestDue,
                'fees_due' => 0,
                'total_due' => $totalDue,
                'status' => 'pending',
            ]));
        }

        $totalRepayable = $schedules->sum('total_due');
        $loan->update([
            'total_repayable' => round($totalRepayable, 2),
            'outstanding_principal' => $principal,
            'outstanding_interest' => round($totalRepayable - $principal, 2),
            'next_due_date' => $schedules->first()?->due_date,
            'maturity_date' => $schedules->last()?->due_date,
        ]);

        return $schedules;
    }
}
