<?php
declare(strict_types=1);

namespace App\Modules\Installments\Services;

use App\Modules\Rules\Services\RuleEngine;

final class InstallmentCalculator
{
    /**
     * Calculate a full installment plan with schedule.
     */
    public static function calculate(string $totalAmount, string $downPayment, int $months, ?string $startDate = null): array
    {
        $interestData = RuleEngine::get('INSTALLMENT_INTEREST_RATE');
        $annualRate = $interestData['percentage'] ?? '22.00';

        $minDownData = RuleEngine::get('INSTALLMENT_MIN_DOWN_PAYMENT');
        $minDownPct = $minDownData['percentage'] ?? '25.00';

        $maxMonthsData = RuleEngine::get('INSTALLMENT_MAX_MONTHS');
        $maxMonths = $maxMonthsData['months'] ?? 30;

        $errors = [];

        // Validate down payment >= 25%
        $minDown = bcdiv(bcmul($totalAmount, $minDownPct, 4), '100', 2);
        if (bccomp($downPayment, $minDown, 2) < 0) {
            $errors[] = "الحد الأدنى للمقدم {$minDownPct}% = " . number_format((float) $minDown, 2) . ' ج.م';
        }

        if (bccomp($downPayment, $totalAmount, 2) >= 0) {
            $errors[] = 'المقدم لا يمكن أن يكون أكبر من أو يساوي المبلغ الكلي';
        }

        if ($months < 1 || $months > $maxMonths) {
            $errors[] = "عدد الأقساط يجب أن يكون بين 1 و {$maxMonths} شهر";
        }

        if (!empty($errors)) {
            return ['success' => false, 'errors' => $errors];
        }

        $remaining = bcsub($totalAmount, $downPayment, 2);
        $startDate = $startDate ?: date('Y-m-d');

        // Calculate interest on remaining balance
        // Simple interest: total_interest = remaining * (annual_rate/100) * (months/12)
        $monthlyRate = bcdiv($annualRate, '1200', 10); // annual / 12 / 100
        $totalInterest = '0.00';

        // Generate schedule with diminishing balance interest
        $schedule = [];
        $monthlyPrincipal = bcdiv($remaining, (string) $months, 2);
        $runningBalance = $remaining;

        for ($i = 1; $i <= $months; $i++) {
            $interestForMonth = bcmul($runningBalance, $monthlyRate, 2);
            $totalInterest = bcadd($totalInterest, $interestForMonth, 2);
            $monthlyTotal = bcadd($monthlyPrincipal, $interestForMonth, 2);

            // Last month: adjust for rounding
            if ($i === $months) {
                $monthlyPrincipal = $runningBalance;
                $monthlyTotal = bcadd($monthlyPrincipal, $interestForMonth, 2);
            }

            $runningBalance = bcsub($runningBalance, $monthlyPrincipal, 2);
            if (bccomp($runningBalance, '0', 2) < 0) {
                $runningBalance = '0.00';
            }

            $dueDate = date('Y-m-d', strtotime($startDate . " +{$i} months"));

            $schedule[] = [
                'number'          => $i,
                'due_date'        => $dueDate,
                'amount'          => $monthlyTotal,
                'principal'       => $monthlyPrincipal,
                'interest'        => $interestForMonth,
                'remaining_after' => $runningBalance,
            ];
        }

        $totalWithInterest = bcadd($remaining, $totalInterest, 2);
        $avgMonthly = $months > 0 ? bcdiv($totalWithInterest, (string) $months, 2) : '0.00';

        // Cash settlement date (30 days from start)
        $cashWindowData = RuleEngine::get('CASH_PAYMENT_WINDOW');
        $cashDays = $cashWindowData['days'] ?? 30;
        $cashSettlementDate = date('Y-m-d', strtotime($startDate . " +{$cashDays} days"));

        return [
            'success'             => true,
            'total_amount'        => $totalAmount,
            'down_payment'        => $downPayment,
            'remaining_balance'   => $remaining,
            'interest_rate'       => $annualRate,
            'total_interest'      => $totalInterest,
            'total_with_interest' => $totalWithInterest,
            'number_of_months'    => $months,
            'monthly_payment'     => $avgMonthly,
            'start_date'          => $startDate,
            'cash_settlement_date'=> $cashSettlementDate,
            'cash_days'           => $cashDays,
            'schedule'            => $schedule,
        ];
    }

    /**
     * Calculate early payoff: remaining principal with zero further interest.
     */
    public static function calculateEarlyPayoff(int $planId): array
    {
        $remainingPrincipal = '0.00';
        $db = \App\Core\App::getInstance()->db();
        $items = $db->select(
            "SELECT * FROM installment_schedule WHERE installment_plan_id = ? AND status IN ('pending','overdue') ORDER BY installment_number ASC",
            [$planId]
        );

        foreach ($items as $item) {
            $remainingPrincipal = bcadd($remainingPrincipal, $item['principal'], 2);
        }

        // Only first pending item's interest is due (current month)
        $currentInterest = '0.00';
        if (!empty($items)) {
            $currentInterest = $items[0]['interest'] ?? '0.00';
        }

        $totalDue = bcadd($remainingPrincipal, $currentInterest, 2);

        return [
            'remaining_principal' => $remainingPrincipal,
            'current_interest'    => $currentInterest,
            'total_early_payoff'  => $totalDue,
            'items_remaining'     => count($items),
            'interest_saved'      => bcsub(
                array_reduce($items, fn($carry, $i) => bcadd($carry, $i['interest'], 2), '0.00'),
                $currentInterest,
                2
            ),
        ];
    }
}