<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\LoanInstallment;
use App\Models\LoanSetting;
use Carbon\Carbon;
use Illuminate\Http\Request;

class OverdueController extends Controller
{
    /**
     * Display overdue EMI list.
     */
    public function index(Request $request)
    {
        $today = today();

        $settings = LoanSetting::first();

        $fineType = $settings->overdue_fine_type ?? 'fixed';
        $fineAmount = (float) ($settings->overdue_fine_amount ?? 0);
        $graceDays = (int) ($settings->overdue_grace_days ?? 0);
        $maxFine = (float) ($settings->overdue_max_fine ?? 0);

        $query = LoanInstallment::with([
            'loan.user',
        ])
            ->whereIn('status', [
                'pending',
                'partial',
                'overdue',
            ])
            ->whereDate('due_date', '<', $today)
            ->where('outstanding_amount', '>', 0)
            ->orderBy('due_date')
            ->orderBy('installment_number');

        if ($request->filled('search')) {

            $search = trim($request->search);

            $query->where(function ($q) use ($search) {

                $q->whereHas('loan', function ($loanQuery) use ($search) {

                    $loanQuery
                        ->where('loan_number', 'like', "%{$search}%")
                        ->orWhereHas('user', function ($userQuery) use ($search) {

                            $userQuery
                                ->where('name', 'like', "%{$search}%")
                                ->orWhere('mobile', 'like', "%{$search}%")
                                ->orWhere('email', 'like', "%{$search}%");
                        });
                });

            });
        }

        $installments = $query
            ->paginate(20)
            ->withQueryString();

        /*
        |--------------------------------------------------------------------------
        | Calculate overdue details
        |--------------------------------------------------------------------------
        */

        $installments->getCollection()->transform(
            function ($installment) use (
                $today,
                $fineType,
                $fineAmount,
                $graceDays,
                $maxFine
            ) {

                $dueDate = Carbon::parse($installment->due_date);

                $calendarDaysOverdue =
                    max(
                        0,
                        $dueDate->diffInDays($today)
                    );

                $chargeableDays =
                    max(
                        0,
                        $calendarDaysOverdue - $graceDays
                    );

                $outstanding =
                    round(
                        (float) $installment->outstanding_amount,
                        2
                    );

                /*
                |--------------------------------------------------------------------------
                | Fine
                |--------------------------------------------------------------------------
                |
                | Fixed:
                |     Fine Amount is charged once after grace period.
                |
                | Percentage:
                |     Fine Amount % of outstanding amount.
                |
                */

                $fine = 0;

                if ($chargeableDays > 0) {

                    if ($fineType === 'percentage') {

                        $fine =
                            round(
                                $outstanding
                                * ($fineAmount / 100),
                                2
                            );

                    } else {

                        $fine =
                            round(
                                $fineAmount,
                                2
                            );
                    }
                }

                /*
                |--------------------------------------------------------------------------
                | Maximum Fine
                |--------------------------------------------------------------------------
                */

                if ($maxFine > 0) {

                    $fine =
                        min(
                            $fine,
                            $maxFine
                        );
                }

                $installment->overdue_days =
                    $calendarDaysOverdue;

                $installment->chargeable_days =
                    $chargeableDays;

                $installment->fine_amount =
                    round($fine, 2);

                $installment->total_payable =
                    round(
                        $outstanding + $fine,
                        2
                    );

                return $installment;
            }
        );

        /*
        |--------------------------------------------------------------------------
        | Statistics
        |--------------------------------------------------------------------------
        */

        $overdueCount = LoanInstallment::query()
            ->whereIn('status', [
                'pending',
                'partial',
                'overdue',
            ])
            ->whereDate('due_date', '<', $today)
            ->where('outstanding_amount', '>', 0)
            ->count();

        $overdueOutstanding = LoanInstallment::query()
            ->whereIn('status', [
                'pending',
                'partial',
                'overdue',
            ])
            ->whereDate('due_date', '<', $today)
            ->where('outstanding_amount', '>', 0)
            ->sum('outstanding_amount');

        return view(
            'admin.overdue.index',
            compact(
                'installments',
                'settings',
                'overdueCount',
                'overdueOutstanding',
                'fineType',
                'fineAmount',
                'graceDays',
                'maxFine'
            )
        );
    }
}