<?php
declare(strict_types=1);

namespace App\Modules\Installments\Services;

use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Members\Services\BoardOfferService;

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;

        $offerOverrides = BoardOfferService::getInstallmentOverrides();
        if (!empty($offerOverrides)) {
            if (isset($offerOverrides['max_months'])) $maxMonths = $offerOverrides['max_months'];
            if (isset($offerOverrides['interest_rate'])) $annualRate = $offerOverrides['interest_rate'];
        }

        $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');

        // Flat simple interest: remaining × (annual_rate/100) × (months/12)
        $totalInterest = bcmul(
            bcmul($remaining, bcdiv($annualRate, '100', 10), 10),
            bcdiv((string) $months, '12', 10),
            2
        );
        $totalWithInterest = bcadd($remaining, $totalInterest, 2);
        $monthlyPayment = bcdiv($totalWithInterest, (string) $months, 2);

        // Per-instalment: equal share of interest, flat principal
        $monthlyPrincipal = bcdiv($remaining, (string) $months, 2);
        $monthlyInterest   = bcdiv($totalInterest, (string) $months, 2);

        $schedule = [];
        $runningBalance = $remaining;

        for ($i = 1; $i <= $months; $i++) {
            $isLast = ($i === $months);
            $principal = $isLast ? $runningBalance : $monthlyPrincipal;
            $interest  = $isLast
                ? bcsub($totalWithInterest, bcadd($remaining, bcsub($totalInterest, $monthlyInterest, 2), 2), 2) // absorb rounding
                : $monthlyInterest;
            if (bccomp($interest, '0', 2) < 0) $interest = '0.00';
            $amount = bcadd($principal, $interest, 2);

            $runningBalance = bcsub($runningBalance, $principal, 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'          => $amount,
                'principal'       => $principal,
                'interest'        => $interest,
                'remaining_after' => $runningBalance,
            ];
        }

        $avgMonthly = $monthlyPayment;

        // 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
            ),
        ];
    }
}