<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use App\Models\Loan;
use App\Models\Client;
use App\Models\ClientGroup;
use App\Models\SavingsAccount;
use App\Models\LoanProduct;
use App\Models\User;
use App\Models\LoanRepayment;
use App\Models\LoanReschedule;
use App\Models\LoanCollateral;
use App\Models\LoanGuarantor;
use App\Http\Requests\StoreLoanRequest;
use App\Mail\LoanApproved;
use App\Mail\LoanRejected;
use App\Mail\LoanWaitForInfo;
use App\Mail\LoanDisbursed;
use App\Mail\LoanRepaymentReceived;
use Carbon\Carbon;
use PDF;

/**
 * Loan Management Controller
 *
 * Handles all loan-related operations including CRUD operations, status management,
 * repayment processing, rescheduling, and reporting for the loan management system.
 *
 * Features:
 * - Loan application creation and management
 * - Loan approval, rejection, disbursement workflow
 * - Repayment tracking and processing
 * - Loan rescheduling and restructuring
 * - Collateral and guarantor management
 * - PDF reporting and printing
 * - Email notifications
 *
 * @package App\Http\Controllers
 */
class LoanController extends Controller
{
    // ========================================
    // CRUD OPERATIONS
    // ========================================

    /**
     * Display loans list with filtering and search.
     * Shows loans with client details, supports search by loan number/client info,
     * filters by status/type/dates, includes statistics.
     */
    public function index()
    {
        // Build query with relationships
        $query = Loan::with(['client', 'loanProduct', 'collaterals', 'guarantors'])
            ->orderBy('created_at', 'desc');

        // Apply search filter
        if ($search = request('search')) {
            $query->where(function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhere('purpose', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('client_number', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                  });
            });
        }

        // Apply filters
        $query->when(request('status'), fn($q) => $q->where('status', request('status')))
              ->when(request('loan_type'), fn($q) => $q->where('loan_type', request('loan_type')))
              ->when(request('start_date'), fn($q) => $q->whereDate('application_date', '>=', request('start_date')))
              ->when(request('end_date'), fn($q) => $q->whereDate('application_date', '<=', request('end_date')));

        $loans = $query->paginate(15);

        // Calculate loan statistics
        $stats = [
            'total' => Loan::count(),
            'pending' => Loan::where('status', 'pending')->count(),
            'approved' => Loan::where('status', 'approved')->count(),
            'disbursed' => Loan::where('status', 'disbursed')->count(),
            'rejected' => Loan::where('status', 'rejected')->count(),
            'active' => Loan::where('status', 'active')->count(),
            'completed' => Loan::where('status', 'completed')->count(),
            'paused' => Loan::where('status', 'paused')->count(),
            'closed' => Loan::where('status', 'closed')->count(),
            'total_amount' => Loan::sum('amount'),
            'pending_amount' => Loan::where('status', 'pending')->sum('amount'),
            'approved_amount' => Loan::where('status', 'approved')->sum('amount'),
            'disbursed_amount' => Loan::where('status', 'disbursed')->sum('amount'),
            'active_amount' => Loan::where('status', 'active')->sum('amount'),
        ];

        return view('loans.index', compact('loans', 'stats'));
    }

    /**
     * Show edit/delete form for loans with search filters
     */
    public function editDelete(Request $request)
    {
        $query = Loan::with(['client', 'creator']);

        // Apply search filters
        $query->when($request->filled('loan_number'), fn($q) => $q->where('loan_number', 'like', '%' . $request->loan_number . '%'))
              ->when($request->filled('client_name'), function($q) use ($request) {
                  $q->whereHas('client', fn($q2) => $q2->where('first_name', 'like', '%' . $request->client_name . '%')
                                                     ->orWhere('last_name', 'like', '%' . $request->client_name . '%'));
              })
              ->when($request->filled('status'), fn($q) => $q->where('status', $request->status));

        $loans = $query->paginate(20);

        return view('loans.edit-delete', compact('loans'));
    }

    public function create()
    {
        $clients = Client::select('id', 'first_name', 'last_name', 'client_number', 'email', 'phone')
            ->where('status', 'active')
            ->orderBy('first_name')
            ->get();

        return view('loans.create', compact('clients'));
    }

    public function createGroup()
    {
        $clientGroups = ClientGroup::select('id', 'name', 'code')
            ->where('status', 'active')
            ->orderBy('name')
            ->get();

        return view('loans.grouploancreate', compact('clientGroups'));
    }

    /**
     * Store new individual loan application
     */
    public function store(Request $request)
    {
        try {
            DB::beginTransaction();

            // Validate input data
            $validated = $request->validate([
                'client_id' => 'required|exists:clients,id',
                'amount' => 'required|numeric|min:50|max:1000000',
                'interest_rate' => 'required|numeric|min:0.1|max:50',
                'duration_months' => 'required|integer|min:1|max:360',
                'loan_type' => 'required|in:personal,business,education,emergency,mortgage,auto,agriculture,group',
                'repayment_frequency' => 'required|in:monthly,weekly,biweekly,quarterly',
                'application_date' => 'required|date',
                'purpose' => 'required|string|min:10|max:1000',
                'monthly_income' => 'nullable|numeric|min:0',
                'employment_status' => 'nullable|string|max:255',
                'notes' => 'nullable|string|max:1000',
                'collateral_type.*' => 'nullable|string|max:255',
                'collateral_value.*' => 'nullable|numeric|min:0',
                'collateral_description.*' => 'nullable|string|max:500',
                'guarantor_name.*' => 'nullable|string|max:255',
                'guarantor_phone.*' => 'nullable|string|max:20',
                'guarantor_email.*' => 'nullable|email|max:255',
                'guarantor_address.*' => 'nullable|string|max:500',
                'guarantor_relationship.*' => 'nullable|string|max:255',
                'guarantor_id_number.*' => 'nullable|string|max:255',
            ]);

            // Calculate loan payments
            $calculations = $this->calculateAmortizedLoan(
                $request->amount,
                $request->interest_rate,
                $request->duration_months,
                $request->repayment_frequency
            );

            // Create loan record
            $loan = Loan::create([
                'client_id' => $request->client_id,
                'client_group_id' => $request->client_group_id ?? null,
                'loan_number' => $this->generateLoanNumber(),
                'amount' => $request->amount,
                'interest_rate' => $request->interest_rate,
                'duration_months' => $request->duration_months,
                'purpose' => $request->purpose,
                'application_date' => $request->application_date,
                'repayment_date' => $this->calculateFirstRepaymentDate($request->application_date, $request->repayment_frequency),
                'status' => 'pending',
                'loan_type' => $request->loan_type,
                'repayment_frequency' => $request->repayment_frequency,
                'monthly_payment' => $calculations['monthly_payment'],
                'total_repayment' => $calculations['total_repayment'],
                'outstanding_balance' => $calculations['total_repayment'],
                'total_interest' => $calculations['total_interest'],
                'monthly_income' => $request->monthly_income,
                'employment_status' => $request->employment_status,
                'remarks' => $request->notes,
                'created_by' => Auth::id(),
            ]);

            // Create collateral records if provided
            if ($request->collateral_type && is_array($request->collateral_type)) {
                foreach ($request->collateral_type as $index => $type) {
                    if (!empty($type)) {
                        LoanCollateral::create([
                            'loan_id' => $loan->id,
                            'type' => $type,
                            'description' => $request->collateral_description[$index] ?? '',
                            'value' => $request->collateral_value[$index] ?? 0,
                            'condition' => 'good',
                        ]);
                    }
                }
            }

            // Create guarantor records if provided
            if ($request->guarantor_name && is_array($request->guarantor_name)) {
                foreach ($request->guarantor_name as $index => $name) {
                    if (!empty($name)) {
                        LoanGuarantor::create([
                            'loan_id' => $loan->id,
                            'name' => $name,
                            'phone' => $request->guarantor_phone[$index] ?? '',
                            'email' => $request->guarantor_email[$index] ?? null,
                            'address' => $request->guarantor_address[$index] ?? '',
                            'relationship' => $request->guarantor_relationship[$index] ?? '',
                            'id_number' => $request->guarantor_id_number[$index] ?? null,
                        ]);
                    }
                }
            }

            DB::commit();

            // Log success and redirect
            Log::info('Loan created successfully', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'client_id' => $loan->client_id,
                'amount' => $loan->amount,
            ]);

            return redirect()->route('loans.show', $loan)
                ->with('success', 'Loan application submitted successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to create loan', [
                'error' => $e->getMessage(),
                'request_data' => $request->all()
            ]);

            return back()->withInput()
                ->with('error', 'Failed to create loan application: ' . $e->getMessage());
        }
    }

    public function storeGroup(Request $request)
    {
        try {
            DB::beginTransaction();

            $validated = $request->validate([
                'client_group_id' => 'required|exists:client_groups,id',
                'amount' => 'required|numeric|min:50|max:1000000',
                'interest_rate' => 'required|numeric|min:0.1|max:50',
                'duration_months' => 'required|integer|min:1|max:360',
                'loan_type' => 'required|in:group',
                'repayment_frequency' => 'required|in:monthly,weekly,biweekly,quarterly',
                'application_date' => 'required|date',
                'purpose' => 'required|string|min:10|max:1000',
                'notes' => 'nullable|string|max:1000',
                'collateral_type.*' => 'nullable|string|max:255',
                'collateral_value.*' => 'nullable|numeric|min:0',
                'collateral_description.*' => 'nullable|string|max:500',
                'guarantor_name.*' => 'nullable|string|max:255',
                'guarantor_phone.*' => 'nullable|string|max:20',
                'guarantor_email.*' => 'nullable|email|max:255',
                'guarantor_address.*' => 'nullable|string|max:500',
                'guarantor_relationship.*' => 'nullable|string|max:255',
                'guarantor_id_number.*' => 'nullable|string|max:255',
            ]);

            $calculations = $this->calculateAmortizedLoan(
                $request->amount,
                $request->interest_rate,
                $request->duration_months,
                $request->repayment_frequency
            );

            $loan = Loan::create([
                'client_group_id' => $request->client_group_id,
                'loan_number' => $this->generateLoanNumber(),
                'amount' => $request->amount,
                'interest_rate' => $request->interest_rate,
                'duration_months' => $request->duration_months,
                'purpose' => $request->purpose,
                'application_date' => $request->application_date,
                'repayment_date' => $this->calculateFirstRepaymentDate($request->application_date, $request->repayment_frequency),
                'status' => 'pending',
                'loan_type' => $request->loan_type,
                'repayment_frequency' => $request->repayment_frequency,
                'monthly_payment' => $calculations['monthly_payment'],
                'total_repayment' => $calculations['total_repayment'],
                'outstanding_balance' => $calculations['total_repayment'],
                'total_interest' => $calculations['total_interest'],
                'remarks' => $request->notes,
                'created_by' => Auth::id(),
            ]);

            // Create collateral records if provided
            if ($request->collateral_type && is_array($request->collateral_type)) {
                foreach ($request->collateral_type as $index => $type) {
                    if (!empty($type)) {
                        LoanCollateral::create([
                            'loan_id' => $loan->id,
                            'type' => $type,
                            'description' => $request->collateral_description[$index] ?? '',
                            'value' => $request->collateral_value[$index] ?? 0,
                            'condition' => 'good',
                        ]);
                    }
                }
            }

            // Create guarantor records if provided
            if ($request->guarantor_name && is_array($request->guarantor_name)) {
                foreach ($request->guarantor_name as $index => $name) {
                    if (!empty($name)) {
                        LoanGuarantor::create([
                            'loan_id' => $loan->id,
                            'name' => $name,
                            'phone' => $request->guarantor_phone[$index] ?? '',
                            'email' => $request->guarantor_email[$index] ?? null,
                            'address' => $request->guarantor_address[$index] ?? '',
                            'relationship' => $request->guarantor_relationship[$index] ?? '',
                            'id_number' => $request->guarantor_id_number[$index] ?? null,
                        ]);
                    }
                }
            }

            DB::commit();

            Log::info('Group loan created successfully', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'client_group_id' => $loan->client_group_id,
                'amount' => $loan->amount,
            ]);

            return redirect()->route('loans.show', $loan)
                ->with('success', 'Group loan application submitted successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to create group loan', [
                'error' => $e->getMessage(),
                'request_data' => $request->all()
            ]);

            return back()->withInput()
                ->with('error', 'Failed to create group loan application: ' . $e->getMessage());
        }
    }

    /**
     * Calculate payment amounts: periodic payment, total repayment, and total interest
     */
    private function calculateAmortizedLoan($principal, $annualRate, $months, $frequency = 'monthly')
    {
        if ($principal <= 0 || $annualRate <= 0 || $months <= 0) {
            return [
                'monthly_payment' => 0,
                'total_repayment' => $principal,
                'total_interest' => 0,
            ];
        }

        // Adjust for repayment frequency
        $paymentsPerYear = $this->getPaymentsPerYear($frequency);
        $periodicRate = $annualRate / 100 / $paymentsPerYear;
        $totalPayments = $months * ($paymentsPerYear / 12);

        if ($periodicRate > 0) {
            $periodicPayment = ($principal * $periodicRate * pow(1 + $periodicRate, $totalPayments)) / (pow(1 + $periodicRate, $totalPayments) - 1);
        } else {
            $periodicPayment = $principal / $totalPayments;
        }

        $totalRepayment = $periodicPayment * $totalPayments;
        $totalInterest = $totalRepayment - $principal;

        return [
            'monthly_payment' => round($periodicPayment, 2),
            'total_repayment' => round($totalRepayment, 2),
            'total_interest' => round($totalInterest, 2),
        ];
    }

    /**
     * Map repayment frequency string to number of payments per year
     */
    private function getPaymentsPerYear($frequency)
    {
        return match($frequency) {
            'weekly' => 52,
            'biweekly' => 26,
            'monthly' => 12,
            'quarterly' => 4,
            default => 12,
        };
    }

    /**
     * Return the first repayment date based on application date and frequency
     */
    private function calculateFirstRepaymentDate($applicationDate, $frequency)
    {
        $date = Carbon::parse($applicationDate);

        return match($frequency) {
            'weekly' => $date->addWeek(),
            'biweekly' => $date->addWeeks(2),
            'monthly' => $date->addMonth(),
            'quarterly' => $date->addMonths(3),
            default => $date->addMonth(),
        };
    }

    public function calculateLoan(Request $request)
    {
        $request->validate([
            'amount' => 'required|numeric|min:1',
            'interest_rate' => 'required|numeric|min:0',
            'duration_months' => 'required|integer|min:1',
            'repayment_frequency' => 'required|in:monthly,weekly,biweekly,quarterly',
        ]);

        $calculations = $this->calculateAmortizedLoan(
            $request->amount,
            $request->interest_rate,
            $request->duration_months,
            $request->repayment_frequency
        );

        return response()->json([
            'success' => true,
            'calculations' => $calculations,
            'schedule' => $this->generateAmortizationSchedule(
                $request->amount,
                $request->interest_rate,
                $request->duration_months,
                $request->repayment_frequency
            )
        ]);
    }

    /**
     * Build the amortization schedule: dates, interest and principal breakdown for each payment
     */
    private function generateAmortizationSchedule($principal, $annualRate, $months, $frequency = 'monthly')
    {
        $calculations = $this->calculateAmortizedLoan($principal, $annualRate, $months, $frequency);
        $periodicPayment = $calculations['monthly_payment'];
        $paymentsPerYear = $this->getPaymentsPerYear($frequency);
        $periodicRate = $annualRate / 100 / $paymentsPerYear;
        $totalPayments = $months * ($paymentsPerYear / 12);

        $balance = $principal;
        $schedule = [];
        $currentDate = now();

        for ($i = 1; $i <= $totalPayments; $i++) {
            $interestPayment = $balance * $periodicRate;
            $principalPayment = $periodicPayment - $interestPayment;
            $balance -= $principalPayment;

            // Calculate due date based on frequency
            $dueDate = match($frequency) {
                'weekly' => $currentDate->copy()->addWeeks($i),
                'biweekly' => $currentDate->copy()->addWeeks($i * 2),
                'monthly' => $currentDate->copy()->addMonths($i),
                'quarterly' => $currentDate->copy()->addMonths($i * 3),
                default => $currentDate->copy()->addMonths($i),
            };

            $schedule[] = [
                'payment_number' => $i,
                'due_date' => $dueDate->format('Y-m-d'),
                'payment_amount' => round($periodicPayment, 2),
                'principal' => round($principalPayment, 2),
                'interest' => round($interestPayment, 2),
                'balance' => round(max(0, $balance), 2),
            ];
        }

        return $schedule;
    }

    /**
     * Show loan details with calculations and performance metrics
     */
    public function show(Loan $loan)
    {
        $loan->load(['client', 'loanProduct', 'repayments', 'reschedules', 'collaterals', 'guarantors', 'creator']);

        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = max(0, $loan->total_repayment - $totalPaid);
        $nextDueDate = $this->calculateNextDueDate($loan);
        $daysOverdue = $this->calculateDaysOverdue($loan);

        // Calculate loan performance metrics
        $performance = $this->calculateLoanPerformance($loan);

        return view('loans.show', compact('loan', 'totalPaid', 'remainingBalance', 'nextDueDate', 'daysOverdue', 'performance'));
    }

    /**
     * Show public loan details for clients (via signed URLs)
     * Displays loan information without sensitive admin actions
     */
    public function showPublic(Loan $loan)
    {
        $loan->load(['client', 'repayments', 'reschedules', 'collaterals', 'guarantors']);

        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = max(0, $loan->total_repayment - $totalPaid);
        $nextDueDate = $this->calculateNextDueDate($loan);
        $daysOverdue = $this->calculateDaysOverdue($loan);

        // Calculate loan performance metrics
        $performance = $this->calculateLoanPerformance($loan);

        return view('loans.show-public', compact('loan', 'totalPaid', 'remainingBalance', 'nextDueDate', 'daysOverdue', 'performance'));
    }

    private function calculateDaysOverdue(Loan $loan)
    {
        if (!in_array($loan->status, ['disbursed', 'active'])) {
            return 0;
        }

        $lastRepayment = $loan->repayments()->orderBy('payment_date', 'desc')->first();
        $lastPaymentDate = $lastRepayment ? $lastRepayment->payment_date : $loan->disbursement_date;

        if (!$lastPaymentDate) {
            return 0;
        }

        $nextDueDate = $lastPaymentDate->copy()->addMonth();
        $today = now();

        if ($today->gt($nextDueDate)) {
            return $today->diffInDays($nextDueDate);
        }

        return 0;
    }

    private function calculateLoanPerformance(Loan $loan)
    {
        $totalPaid = $loan->repayments->sum('amount');
        $expectedPayments = $this->calculateExpectedPayments($loan);
        $ontimePayments = $loan->repayments()->where('status', 'ontime')->count();

        return [
            'payment_rate' => $expectedPayments > 0 ? ($ontimePayments / $expectedPayments) * 100 : 0,
            'completion_rate' => $loan->total_repayment > 0 ? ($totalPaid / $loan->total_repayment) * 100 : 0,
            'average_payment' => $loan->repayments->count() > 0 ? $totalPaid / $loan->repayments->count() : 0,
        ];
    }

    private function calculateExpectedPayments(Loan $loan)
    {
        if (!$loan->disbursement_date) {
            return 0;
        }

        $monthsSinceDisbursement = $loan->disbursement_date->diffInMonths(now());
        return min($monthsSinceDisbursement, $loan->duration_months);
    }

    public function edit(Loan $loan)
    {
        if (!in_array($loan->status, ['pending', 'approved'])) {
            return redirect()->route('loans.show', $loan)
                ->with('error', 'Loan cannot be edited in its current status.');
        }

        $clients = Client::select('id', 'first_name', 'last_name', 'client_number')
            ->orderBy('first_name')
            ->get();

        $loan->load(['collaterals', 'guarantors']);

        return view('loans.edit', compact('loan', 'clients'));
    }

    public function update(Request $request, Loan $loan)
    {
        if (!in_array($loan->status, ['pending', 'approved'])) {
            return back()->with('error', 'Loan cannot be edited in its current status.');
        }

        $request->validate([
            'amount' => 'required|numeric|min:50|max:1000000',
            'interest_rate' => 'required|numeric|min:0.1|max:50',
            'duration_months' => 'required|integer|min:1|max:360',
            'purpose' => 'required|string|min:10|max:500',
            'loan_type' => 'required|in:personal,business,education,emergency,mortgage,auto,agriculture',
            'repayment_frequency' => 'required|in:monthly,weekly,biweekly,quarterly',
            'monthly_income' => 'nullable|numeric|min:0',
            'employment_status' => 'nullable|string|max:255',
            'notes' => 'nullable|string|max:1000',
        ]);

        try {
            DB::beginTransaction();

            $loan->update($request->only([
                'amount', 'interest_rate', 'duration_months', 'purpose', 'loan_type',
                'repayment_frequency', 'monthly_income', 'employment_status', 'remarks'
            ]));

            $calculations = $this->calculateAmortizedLoan(
                $loan->amount,
                $loan->interest_rate,
                $loan->duration_months,
                $loan->repayment_frequency
            );

            $loan->update([
                'monthly_payment' => $calculations['monthly_payment'],
                'total_repayment' => $calculations['total_repayment'],
                'outstanding_balance' => $calculations['total_repayment'],
                'total_interest' => $calculations['total_interest'],
            ]);

            DB::commit();

            Log::info('Loan updated successfully', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number
            ]);

            return redirect()->route('loans.show', $loan)
                ->with('success', 'Loan updated successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to update loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->withInput()
                ->with('error', 'Failed to update loan: ' . $e->getMessage());
        }
    }

    public function destroy(Loan $loan)
    {
        if (!in_array($loan->status, ['pending', 'rejected'])) {
            return back()->with('error', 'Only pending or rejected loans can be deleted.');
        }

        try {
            DB::beginTransaction();

            // Delete related records
            $loan->collaterals()->delete();
            $loan->guarantors()->delete();
            $loan->repayments()->delete();
            $loan->reschedules()->delete();

            $loan->delete();

            DB::commit();

            Log::info('Loan deleted successfully', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number
            ]);

            return redirect()->route('loans.index')
                ->with('success', 'Loan deleted successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to delete loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to delete loan: ' . $e->getMessage());
        }
    }

    public function addCollateral(Request $request, Loan $loan)
    {
        $request->validate([
            'type' => 'required|string|max:255',
            'description' => 'required|string|max:500',
            'value' => 'required|numeric|min:0',
            'condition' => 'required|string|max:255',
            'document_path' => 'nullable|file|max:10240', // 10MB max
        ]);

        try {
            $collateralData = $request->only(['type', 'description', 'value', 'condition']);

            if ($request->hasFile('document_path')) {
                $path = $request->file('document_path')->store('collateral-documents', 'public');
                $collateralData['document_path'] = $path;
            }

            $collateral = $loan->collaterals()->create($collateralData);

            Log::info('Collateral added to loan', [
                'loan_id' => $loan->id,
                'collateral_id' => $collateral->id
            ]);

            return back()->with('success', 'Collateral added successfully.');

        } catch (\Exception $e) {
            Log::error('Failed to add collateral', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to add collateral: ' . $e->getMessage());
        }
    }

    public function addGuarantor(Request $request, Loan $loan)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'phone' => 'required|string|max:20',
            'email' => 'nullable|email|max:255',
            'address' => 'required|string|max:500',
            'relationship' => 'required|string|max:255',
            'id_number' => 'nullable|string|max:255',
            'id_document_path' => 'nullable|file|max:10240',
        ]);

        try {
            $guarantorData = $request->only(['name', 'phone', 'email', 'address', 'relationship', 'id_number']);

            if ($request->hasFile('id_document_path')) {
                $path = $request->file('id_document_path')->store('guarantor-documents', 'public');
                $guarantorData['id_document_path'] = $path;
            }

            $guarantor = $loan->guarantors()->create($guarantorData);

            Log::info('Guarantor added to loan', [
                'loan_id' => $loan->id,
                'guarantor_id' => $guarantor->id
            ]);

            return back()->with('success', 'Guarantor added successfully.');

        } catch (\Exception $e) {
            Log::error('Failed to add guarantor', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to add guarantor: ' . $e->getMessage());
        }
    }

    private function generateLoanNumber()
    {
        do {
            $number = 'LN' . date('Ymd') . strtoupper(Str::random(6));
        } while (Loan::where('loan_number', $number)->exists());

        return $number;
    }

    // ========================================
    // STATUS MANAGEMENT
    // ========================================

    /**
     * Approve a pending loan application.
     *
     * Updates loan status to 'approved' and sends notification email to client.
     *
     * @param \Illuminate\Http\Request $request
     * @param \App\Models\Loan $loan
     * @return \Illuminate\Http\RedirectResponse
     */
    public function approve(Request $request, Loan $loan)
    {
        // Check permission
        if (!Auth::user()->hasPermission('loans.approve', 'approve')) {
            return back()->with('error', 'You do not have permission to approve loans.');
        }

        try {
            DB::beginTransaction();

            $loan->update([
                'status' => 'approved',
                'approved_at' => now(),
                'approved_by' => Auth::id(),
            ]);

            // Send email notification to client
            if ($loan->client && $loan->client->email) {
                try {
                    Mail::to($loan->client->email)->send(new LoanApproved($loan));
                    Log::info('Loan approval email sent to client', [
                        'loan_id' => $loan->id,
                        'client_email' => $loan->client->email
                    ]);
                } catch (\Exception $emailException) {
                    Log::error('Failed to send loan approval email', [
                        'loan_id' => $loan->id,
                        'error' => $emailException->getMessage()
                    ]);
                }
            }

            DB::commit();

            Log::info('Loan approved', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'approved_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan approved successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to approve loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to approve loan: ' . $e->getMessage());
        }
    }

    public function reject(Request $request, Loan $loan)
    {
        // Check permission
        if (!Auth::user()->hasPermission('loans.reject', 'reject')) {
            return back()->with('error', 'You do not have permission to reject loans.');
        }

        $request->validate([
            'rejection_reason' => 'required|string|max:500'
        ]);

        try {
            DB::beginTransaction();

            $loan->update([
                'status' => 'rejected',
                'rejection_reason' => $request->rejection_reason,
                'rejected_at' => now(),
                'rejected_by' => Auth::id(),
            ]);

            // Send email notification to client
            if ($loan->client && $loan->client->email) {
                try {
                    Mail::to($loan->client->email)->send(new LoanRejected($loan, $request->rejection_reason));
                    Log::info('Loan rejection email sent to client', [
                        'loan_id' => $loan->id,
                        'client_email' => $loan->client->email
                    ]);
                } catch (\Exception $emailException) {
                    Log::error('Failed to send loan rejection email', [
                        'loan_id' => $loan->id,
                        'error' => $emailException->getMessage()
                    ]);
                }
            }

            DB::commit();

            Log::info('Loan rejected', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'rejected_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan rejected.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to reject loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to reject loan: ' . $e->getMessage());
        }
    }

    /**
     * Bulk approve multiple pending loans.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function bulkApprove(Request $request)
    {
        // Check permission
        if (!Auth::user()->hasPermission('loans.approve', 'approve')) {
            return back()->with('error', 'You do not have permission to approve loans.');
        }

        $request->validate([
            'loan_ids' => 'required|string'
        ]);

        $loanIds = explode(',', $request->loan_ids);
        $loanIds = array_filter(array_map('intval', $loanIds));

        if (empty($loanIds)) {
            return back()->with('error', 'No loans selected for approval.');
        }

        try {
            DB::beginTransaction();

            $loans = Loan::whereIn('id', $loanIds)
                        ->where('status', 'pending')
                        ->with('client')
                        ->get();

            $approvedCount = 0;
            $skippedCount = 0;

            foreach ($loans as $loan) {
                // Double-check status in case it changed
                if ($loan->status !== 'pending') {
                    $skippedCount++;
                    continue;
                }

                $loan->update([
                    'status' => 'approved',
                    'approved_at' => now(),
                    'approved_by' => Auth::id(),
                ]);

                // Send email notification to client
                if ($loan->client && $loan->client->email) {
                    try {
                        Mail::to($loan->client->email)->send(new LoanApproved($loan));
                        Log::info('Bulk loan approval email sent to client', [
                            'loan_id' => $loan->id,
                            'client_email' => $loan->client->email
                        ]);
                    } catch (\Exception $emailException) {
                        Log::error('Failed to send bulk loan approval email', [
                            'loan_id' => $loan->id,
                            'error' => $emailException->getMessage()
                        ]);
                    }
                }

                $approvedCount++;
            }

            DB::commit();

            $message = "Successfully approved {$approvedCount} loan(s).";
            if ($skippedCount > 0) {
                $message .= " {$skippedCount} loan(s) were skipped (not in pending status).";
            }

            Log::info('Bulk loan approval completed', [
                'approved_count' => $approvedCount,
                'skipped_count' => $skippedCount,
                'loan_ids' => $loanIds,
                'approved_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', $message);

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to bulk approve loans', [
                'loan_ids' => $loanIds,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to approve loans: ' . $e->getMessage());
        }
    }

    /**
     * Bulk reject multiple pending loans.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function bulkReject(Request $request)
    {
        // Check permission
        if (!Auth::user()->hasPermission('loans.reject', 'reject')) {
            return back()->with('error', 'You do not have permission to reject loans.');
        }

        $request->validate([
            'loan_ids' => 'required|string',
            'reason' => 'required|string|max:500'
        ]);

        $loanIds = explode(',', $request->loan_ids);
        $loanIds = array_filter(array_map('intval', $loanIds));

        if (empty($loanIds)) {
            return back()->with('error', 'No loans selected for rejection.');
        }

        try {
            DB::beginTransaction();

            $loans = Loan::whereIn('id', $loanIds)
                        ->where('status', 'pending')
                        ->with('client')
                        ->get();

            $rejectedCount = 0;
            $skippedCount = 0;

            foreach ($loans as $loan) {
                // Double-check status in case it changed
                if ($loan->status !== 'pending') {
                    $skippedCount++;
                    continue;
                }

                $loan->update([
                    'status' => 'rejected',
                    'rejection_reason' => $request->reason,
                    'rejected_at' => now(),
                    'rejected_by' => Auth::id(),
                ]);

                // Send email notification to client
                if ($loan->client && $loan->client->email) {
                    try {
                        Mail::to($loan->client->email)->send(new LoanRejected($loan, $request->reason));
                        Log::info('Bulk loan rejection email sent to client', [
                            'loan_id' => $loan->id,
                            'client_email' => $loan->client->email
                        ]);
                    } catch (\Exception $emailException) {
                        Log::error('Failed to send bulk loan rejection email', [
                            'loan_id' => $loan->id,
                            'error' => $emailException->getMessage()
                        ]);
                    }
                }

                $rejectedCount++;
            }

            DB::commit();

            $message = "Successfully rejected {$rejectedCount} loan(s).";
            if ($skippedCount > 0) {
                $message .= " {$skippedCount} loan(s) were skipped (not in pending status).";
            }

            Log::info('Bulk loan rejection completed', [
                'rejected_count' => $rejectedCount,
                'skipped_count' => $skippedCount,
                'loan_ids' => $loanIds,
                'rejected_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', $message);

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to bulk reject loans', [
                'loan_ids' => $loanIds,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to reject loans: ' . $e->getMessage());
        }
    }

    public function showWaitForm(Loan $loan)
    {
        // Check if loan is in pending status
        if ($loan->status !== 'pending') {
            return redirect()->route('loans.show', $loan->id)
                ->with('error', 'This action is only available for pending loan applications.');
        }

        return view('loans.wait', compact('loan'));
    }

    public function wait(Request $request, Loan $loan)
    {
        // Check permission
        if (!Auth::user()->hasPermission('loans.wait', 'wait')) {
            return back()->with('error', 'You do not have permission to put loans on wait.');
        }

        // Check if loan is in pending status
        if ($loan->status !== 'pending') {
            return redirect()->route('loans.show', $loan->id)
                ->with('error', 'This action is only available for pending loan applications.');
        }

        $request->validate([
            'wait_reason' => 'required|string|max:500'
        ]);

        try {
            DB::beginTransaction();

            $loan->update([
                'status' => 'waiting',
                'wait_reason' => $request->wait_reason,
                'wait_requested_at' => now(),
                'wait_requested_by' => Auth::id(),
            ]);

            // Send email notification to client
            if ($loan->client && $loan->client->email) {
                try {
                    Mail::to($loan->client->email)->send(new LoanWaitForInfo($loan, $request->wait_reason));
                    Log::info('Loan wait email sent to client', [
                        'loan_id' => $loan->id,
                        'client_email' => $loan->client->email
                    ]);
                } catch (\Exception $emailException) {
                    Log::error('Failed to send loan wait email', [
                        'loan_id' => $loan->id,
                        'error' => $emailException->getMessage()
                    ]);
                }
            }

            DB::commit();

            Log::info('Loan set to waiting status', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'wait_requested_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan application paused. Client has been notified to provide additional information.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to set loan to waiting status', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to pause loan: ' . $e->getMessage());
        }
    }

    /**
     * Disburse approved loan - update status and send email
     */
    public function disburse(Request $request, Loan $loan)
    {
        // Check permission
        if (!Auth::user()->hasPermission('loans.disburse', 'disburse')) {
            return back()->with('error', 'You do not have permission to disburse loans.');
        }

        $request->validate([
            'disbursement_date' => 'required|date',
            'disbursement_method' => 'required|string|max:255',
            'disbursement_reference' => 'nullable|string|max:255',
        ]);

        try {
            DB::beginTransaction();

            // Update loan status to disbursed
            $loan->update([
                'status' => 'disbursed',
                'disbursement_date' => $request->disbursement_date,
                'disbursement_method' => $request->disbursement_method,
                'disbursement_reference' => $request->disbursement_reference,
                'disbursed_at' => now(),
                'disbursed_by' => Auth::id(),
            ]);

            // Send email notification
            if ($loan->client && $loan->client->email) {
                try {
                    Mail::to($loan->client->email)->send(new LoanDisbursed($loan));
                    Log::info('Loan disbursement email sent', [
                        'loan_id' => $loan->id,
                        'client_email' => $loan->client->email
                    ]);
                } catch (\Exception $emailException) {
                    Log::error('Failed to send loan disbursement email', [
                        'loan_id' => $loan->id,
                        'error' => $emailException->getMessage()
                    ]);
                }
            }

            DB::commit();

            Log::info('Loan disbursed', [
                'loan_id' => $loan->id,
                'disbursed_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan disbursed successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to disburse loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to disburse loan: ' . $e->getMessage());
        }
    }

    public function pause(Request $request, Loan $loan)
    {
        try {
            DB::beginTransaction();

            $loan->update([
                'status' => 'paused',
                'paused_at' => now(),
                'paused_by' => Auth::id(),
            ]);

            DB::commit();

            Log::info('Loan paused', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'paused_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan paused successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to pause loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to pause loan: ' . $e->getMessage());
        }
    }

    public function close(Request $request, Loan $loan)
    {
        try {
            DB::beginTransaction();

            $loan->update([
                'status' => 'closed',
                'closed_at' => now(),
                'closed_by' => Auth::id(),
            ]);

            DB::commit();

            Log::info('Loan closed', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'closed_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan closed successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to close loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to close loan: ' . $e->getMessage());
        }
    }

    public function resume(Request $request, Loan $loan)
    {
        // Check if loan is in waiting status
        if ($loan->status !== 'waiting') {
            return redirect()->route('loans.show', $loan->id)
                ->with('error', 'This action is only available for loans waiting for additional information.');
        }

        try {
            DB::beginTransaction();

            $loan->update([
                'status' => 'pending',
                'wait_reason' => null,
                'wait_requested_at' => null,
                'wait_requested_by' => null,
            ]);

            DB::commit();

            Log::info('Loan resumed from waiting status', [
                'loan_id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'resumed_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Loan application resumed successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to resume loan', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to resume loan: ' . $e->getMessage());
        }
    }

    public function createRepayment(Loan $loan)
    {
        // Check if loan is in a status that allows repayments
        if (!in_array($loan->status, ['approved', 'disbursed', 'active'])) {
            return redirect()->route('loans.show', $loan)
                ->with('error', 'Repayments can only be recorded for approved or disbursed loans.');
        }

        $loan->load(['client', 'repayments']);
        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = max(0, $loan->total_repayment - $totalPaid);
        $nextDueDate = $this->calculateNextDueDate($loan);

        return view('loans.repayment-create', compact('loan', 'totalPaid', 'remainingBalance', 'nextDueDate'));
    }

    public function storeRepayment(Request $request, Loan $loan)
    {
        // Check if loan is in a status that allows repayments
        if (!in_array($loan->status, ['approved', 'disbursed', 'active'])) {
            return redirect()->route('loans.show', $loan)
                ->with('error', 'Repayments can only be recorded for approved or disbursed loans.');
        }

        // Base validation
        $request->validate([
            'amount' => 'required|numeric|min:0.01',
            'repayment_date' => 'required|date',
            'payment_method' => 'required|in:cash,bank_transfer,mobile_money,cheque',
        ]);

        // Method-specific validation
        $method = $request->payment_method;
        $additionalValidation = [];

        switch ($method) {
            case 'bank_transfer':
                $additionalValidation = [
                    'bank_name' => 'required|string|max:255',
                    'account_number' => 'required|string|max:255',
                    'reference' => 'required|string|max:255',
                    'transfer_date' => 'required|date',
                ];
                break;
            case 'mobile_money':
                $additionalValidation = [
                    'mobile_provider' => 'required|string|max:255',
                    'mobile_number' => 'required|string|max:20',
                    'reference' => 'required|string|max:255',
                    'mm_transaction_date' => 'required|date',
                ];
                break;
            case 'cheque':
                $additionalValidation = [
                    'cheque_number' => 'required|string|max:255',
                    'cheque_date' => 'required|date',
                    'bank_name_cheque' => 'required|string|max:255',
                    'branch' => 'nullable|string|max:255',
                ];
                break;
            case 'cash':
                $additionalValidation = [
                    'received_by' => 'required|string|max:255',
                    'receipt_number' => 'required|string|max:255',
                ];
                break;
        }

        $request->validate($additionalValidation);

        try {
            DB::beginTransaction();

            // Determine repayment status
            $status = $this->determineRepaymentStatus($loan, $request->repayment_date, $request->amount);

            // Prepare repayment data
            $repaymentData = [
                'loan_id' => $loan->id,
                'amount' => $request->amount,
                'payment_date' => $request->repayment_date,
                'payment_method' => $method,
                'status' => $status,
                'created_by' => Auth::id(),
                'notes' => $request->notes,
            ];

            // Add method-specific data
            $repaymentData['reference'] = match($method) {
                'bank_transfer', 'mobile_money' => $request->reference,
                'cheque' => $request->cheque_number,
                'cash' => $request->receipt_number,
                default => null,
            };

            // Create repayment record
            $repayment = LoanRepayment::create($repaymentData);

            // Update loan outstanding balance
            $totalPaid = $loan->repayments()->sum('amount') + $request->amount;
            $loan->update([
                'outstanding_balance' => max(0, $loan->total_repayment - $totalPaid),
            ]);

            // Update loan status if fully paid
            if ($totalPaid >= $loan->total_repayment) {
                $loan->update(['status' => 'completed']);
            } elseif ($loan->status === 'disbursed') {
                $loan->update(['status' => 'active']);
            }

            // Send email notification to client
            if ($loan->client && $loan->client->email) {
                try {
                    Mail::to($loan->client->email)->send(new LoanRepaymentReceived($loan, $repayment));
                    Log::info('Loan repayment email sent to client', [
                        'loan_id' => $loan->id,
                        'repayment_id' => $repayment->id,
                        'client_email' => $loan->client->email
                    ]);
                } catch (\Exception $emailException) {
                    Log::error('Failed to send loan repayment email', [
                        'loan_id' => $loan->id,
                        'repayment_id' => $repayment->id,
                        'error' => $emailException->getMessage()
                    ]);
                }
            }

            DB::commit();

            Log::info('Loan repayment recorded', [
                'loan_id' => $loan->id,
                'repayment_id' => $repayment->id,
                'amount' => $request->amount,
                'payment_method' => $method,
                'recorded_by' => Auth::id()
            ]);

            return redirect()->route('loans.show', $loan)
                ->with('success', 'Repayment recorded successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to record loan repayment', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage(),
                'request_data' => $request->all()
            ]);

            return back()->withInput()
                ->with('error', 'Failed to record repayment: ' . $e->getMessage());
        }
    }

    private function determineRepaymentStatus(Loan $loan, $paymentDate, $amount)
    {
        $paymentDate = Carbon::parse($paymentDate);
        $nextDueDate = $this->calculateNextDueDate($loan);

        // If payment is on or before due date and full amount
        if ($paymentDate->lte($nextDueDate) && $amount >= $loan->monthly_payment) {
            return 'ontime';
        }

        // If payment is after due date
        if ($paymentDate->gt($nextDueDate)) {
            return 'late';
        }

        // If partial payment
        if ($amount < $loan->monthly_payment) {
            return 'partial';
        }

        return 'ontime'; // Default
    }

    private function calculateNextDueDate(Loan $loan)
    {
        $lastRepayment = $loan->repayments()->orderBy('payment_date', 'desc')->first();

        if ($lastRepayment) {
            return $lastRepayment->payment_date->addDays(30);
        }

        return $loan->disbursement_date ? $loan->disbursement_date->addDays(30) : now()->addDays(30);
    }

    /**
     * List all loan repayments with filtering and statistics
     */
    public function repayments(Request $request)
    {
        $query = LoanRepayment::with(['loan.client', 'creator'])
            ->orderBy('payment_date', 'desc');

        // Apply filters
        if ($search = $request->search) {
            $query->whereHas('loan', function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q2) use ($search) {
                      $q2->where('first_name', 'like', "%{$search}%")
                         ->orWhere('last_name', 'like', "%{$search}%")
                         ->orWhere('client_number', 'like', "%{$search}%");
                  });
            });
        }

        $query->when($request->from_date, fn($q) => $q->where('payment_date', '>=', $request->from_date))
              ->when($request->to_date, fn($q) => $q->where('payment_date', '<=', $request->to_date))
              ->when($request->payment_method, fn($q) => $q->where('payment_method', $request->payment_method));

        $repayments = $query->paginate(15);

        // Calculate statistics
        $totalRepayments = LoanRepayment::count();
        $totalAmount = LoanRepayment::sum('amount');
        $todayRepayments = LoanRepayment::whereDate('payment_date', today())->sum('amount');

        $stats = [
            'total_amount' => $totalAmount,
            'total_transactions' => $totalRepayments,
            'today_amount' => $todayRepayments,
            'average_payment' => $totalRepayments > 0 ? $totalAmount / $totalRepayments : 0,
        ];

        return view('loans.repayments', compact('repayments', 'stats'));
    }

    public function pending(Request $request)
    {
        $query = Loan::with(['client', 'loanProduct'])
            ->whereIn('status', ['pending', 'rejected', 'waiting'])
            ->orderBy('created_at', 'desc');

        if ($request->has('search') && $request->search != '') {
            $search = $request->search;
            $query->where(function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhere('purpose', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('client_number', 'like', "%{$search}%");
                  });
            });
        }

        $loans = $query->paginate(15);

        $stats = [
            'total' => Loan::count(),
            'pending' => Loan::where('status', 'pending')->count(),
            'approved' => Loan::where('status', 'approved')->count(),
            'disbursed' => Loan::where('status', 'disbursed')->count(),
            'rejected' => Loan::where('status', 'rejected')->count(),
            'waiting' => Loan::where('status', 'waiting')->count(),
        ];

        return view('loans.pending', compact('loans', 'stats'));
    }

    public function approved()
    {
        $loans = Loan::with(['client', 'loanProduct'])
            ->where('status', 'approved')
            ->orderBy('created_at', 'desc')
            ->paginate(15);

        $stats = [
            'total' => Loan::count(),
            'pending' => Loan::where('status', 'pending')->count(),
            'approved' => Loan::where('status', 'approved')->count(),
            'disbursed' => Loan::where('status', 'disbursed')->count(),
        ];

        return view('loans.approved', compact('loans', 'stats'));
    }

    public function getClientSavingsAccounts(Client $client)
    {
        $savingsAccounts = SavingsAccount::where('client_id', $client->id)
            ->where('status', 'active')
            ->select('id', 'account_number', 'current_balance', 'type', 'product_name')
            ->get();

        return response()->json($savingsAccounts);
    }

    public function repaymentSchedule(Loan $loan)
    {
        $loan->load(['client', 'repayments']);

        $schedule = [];
        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = $loan->total_repayment;
        $monthlyPayment = $loan->monthly_payment;

        $currentDate = $loan->disbursement_date ?: $loan->created_at;

        for ($i = 1; $i <= $loan->duration_months; $i++) {
            $dueDate = $currentDate->copy()->addMonths($i);
            $paidAmount = 0;
            $status = 'pending';

            $repaymentForPeriod = $loan->repayments()
                ->whereBetween('payment_date', [
                    $dueDate->copy()->subMonth(),
                    $dueDate
                ])->sum('amount');

            if ($repaymentForPeriod > 0) {
                $paidAmount = $repaymentForPeriod;
                $status = 'paid';
            } elseif ($dueDate->lt(now())) {
                $status = 'overdue';
            }

            $remainingBalance -= $monthlyPayment;

            $schedule[] = [
                'installment_number' => $i,
                'due_date' => $dueDate,
                'due_amount' => $monthlyPayment,
                'paid_amount' => $paidAmount,
                'status' => $status,
                'remaining_balance' => max(0, $remainingBalance),
            ];
        }

        return view('loans.repayment-schedule', compact('loan', 'schedule', 'totalPaid'));
    }

    public function createReschedule(Loan $loan)
    {
        $loan->load(['client', 'repayments']);
        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = max(0, $loan->total_repayment - $totalPaid);

        return view('loans.reschedule-create', compact('loan', 'totalPaid', 'remainingBalance'));
    }

    public function storeReschedule(Request $request, Loan $loan)
    {
        $request->validate([
            'reschedule_type' => 'required|in:extend_duration,change_rate,restructure',
            'new_duration' => [
                'required_if:reschedule_type,extend_duration,restructure',
                'integer',
                function ($attribute, $value, $fail) use ($loan, $request) {
                    $min = 1;
                    if ($request->reschedule_type === 'extend_duration') {
                        $min = $loan->duration_months + 1;
                    }
                    if ($value < $min) {
                        $fail("The new duration must be at least $min months.");
                    }
                },
            ],
            'new_interest_rate' => 'required_if:reschedule_type,change_rate,restructure|numeric|min:0',
            'new_amount' => 'required_if:reschedule_type,restructure|numeric|min:0',
            'reason' => 'required|string|max:500',
        ]);

        try {
            DB::beginTransaction();

            $reschedule = LoanReschedule::create([
                'loan_id' => $loan->id,
                'reschedule_type' => $request->reschedule_type,
                'old_amount' => $loan->amount,
                'new_amount' => $request->new_amount ?? $loan->amount,
                'old_duration' => $loan->duration_months,
                'new_duration' => $request->new_duration ?? $loan->duration_months,
                'old_interest_rate' => $loan->interest_rate,
                'new_interest_rate' => $request->new_interest_rate ?? $loan->interest_rate,
                'reschedule_date' => now(),
                'reason' => $request->reason,
                'status' => 'pending',
            ]);

            // For restructure type, apply changes immediately
            if ($request->reschedule_type === 'restructure') {
                $totalPaid = $loan->repayments->sum('amount');

                $loan->update([
                    'amount' => $request->new_amount,
                    'duration_months' => $request->new_duration,
                    'interest_rate' => $request->new_interest_rate,
                ]);

                $calculations = $this->calculateAmortizedLoan(
                    $loan->amount,
                    $loan->interest_rate,
                    $loan->duration_months,
                    $loan->repayment_frequency
                );

                $loan->update([
                    'monthly_payment' => $calculations['monthly_payment'],
                    'total_repayment' => $calculations['total_repayment'],
                    'outstanding_balance' => $calculations['total_repayment'] - $totalPaid,
                ]);

                $reschedule->update([
                    'status' => 'approved',
                    'approved_by' => Auth::id(),
                    'approved_at' => now(),
                ]);

                Log::info('Loan restructure applied immediately', [
                    'loan_id' => $loan->id,
                    'reschedule_id' => $reschedule->id,
                ]);

                return redirect()->route('loans.show', $loan)
                    ->with('success', 'Loan restructured successfully.');
            }

            DB::commit();

            Log::info('Loan reschedule requested', [
                'loan_id' => $loan->id,
                'reschedule_id' => $reschedule->id,
                'type' => $request->reschedule_type,
            ]);

            return redirect()->route('loans.show', $loan)
                ->with('success', 'Reschedule request submitted successfully and is pending approval.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to create reschedule request', [
                'loan_id' => $loan->id,
                'error' => $e->getMessage()
            ]);

            return back()->withInput()
                ->with('error', 'Failed to submit reschedule request: ' . $e->getMessage());
        }
    }

    public function reschedules(Request $request)
    {
        $query = LoanReschedule::with(['loan.client', 'approver'])
            ->orderBy('created_at', 'desc');

        if ($request->has('search') && $request->search) {
            $search = $request->search;
            $query->whereHas('loan', function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q2) use ($search) {
                      $q2->where('first_name', 'like', "%{$search}%")
                         ->orWhere('last_name', 'like', "%{$search}%");
                  });
            });
        }

        if ($request->has('status') && $request->status) {
            $query->where('status', $request->status);
        }

        if ($request->has('reschedule_type') && $request->reschedule_type) {
            $query->where('reschedule_type', $request->reschedule_type);
        }

        $reschedules = $query->paginate(15);

        return view('loans.reschedules', compact('reschedules'));
    }

    public function approveReschedule(Request $request, LoanReschedule $reschedule)
    {
        $request->validate([
            'approval_notes' => 'nullable|string|max:500',
        ]);

        try {
            DB::beginTransaction();

            $reschedule->update([
                'status' => 'approved',
                'approved_by' => Auth::id(),
                'approved_at' => now(),
                'approval_notes' => $request->approval_notes,
            ]);

            $loan = $reschedule->loan;
            $loan->update([
                'amount' => $reschedule->new_amount,
                'duration_months' => $reschedule->new_duration,
                'interest_rate' => $reschedule->new_interest_rate,
            ]);

            $calculations = $this->calculateAmortizedLoan(
                $loan->amount,
                $loan->interest_rate,
                $loan->duration_months,
                $loan->repayment_frequency
            );

            $loan->update([
                'monthly_payment' => $calculations['monthly_payment'],
                'total_repayment' => $calculations['total_repayment'],
                'outstanding_balance' => $calculations['total_repayment'],
            ]);

            DB::commit();

            Log::info('Loan reschedule approved', [
                'reschedule_id' => $reschedule->id,
                'loan_id' => $loan->id,
                'approved_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Reschedule request approved successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Failed to approve reschedule', [
                'reschedule_id' => $reschedule->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to approve reschedule request: ' . $e->getMessage());
        }
    }

    public function rejectReschedule(Request $request, LoanReschedule $reschedule)
    {
        $request->validate([
            'approval_notes' => 'required|string|max:500',
        ]);

        try {
            $reschedule->update([
                'status' => 'rejected',
                'approved_by' => Auth::id(),
                'approved_at' => now(),
                'approval_notes' => $request->approval_notes,
            ]);

            Log::info('Loan reschedule rejected', [
                'reschedule_id' => $reschedule->id,
                'rejected_by' => Auth::id()
            ]);

            return redirect()->back()->with('success', 'Reschedule request rejected.');

        } catch (\Exception $e) {
            Log::error('Failed to reject reschedule', [
                'reschedule_id' => $reschedule->id,
                'error' => $e->getMessage()
            ]);

            return back()->with('error', 'Failed to reject reschedule request: ' . $e->getMessage());
        }
    }

    /**
     * Print all loans with filters applied
     */
    public function printAll(Request $request)
    {
        $query = Loan::with(['client', 'loanProduct', 'collaterals', 'guarantors'])
            ->orderBy('created_at', 'desc');

        // Apply same filters as index method
        if ($search = $request->search) {
            $query->where(function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhere('purpose', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('client_number', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                  });
            });
        }

        $query->when($request->status, fn($q) => $q->where('status', $request->status))
              ->when($request->loan_type, fn($q) => $q->where('loan_type', $request->loan_type))
              ->when($request->start_date, fn($q) => $q->whereDate('application_date', '>=', $request->start_date))
              ->when($request->end_date, fn($q) => $q->whereDate('application_date', '<=', $request->end_date));

        $loans = $query->get();

        // Calculate stats for filtered loans
        $stats = [
            'total' => $loans->count(),
            'pending' => $loans->where('status', 'pending')->count(),
            'approved' => $loans->where('status', 'approved')->count(),
            'disbursed' => $loans->where('status', 'disbursed')->count(),
            'rejected' => $loans->where('status', 'rejected')->count(),
            'active' => $loans->where('status', 'active')->count(),
            'completed' => $loans->where('status', 'completed')->count(),
            'paused' => $loans->where('status', 'paused')->count(),
            'closed' => $loans->where('status', 'closed')->count(),
            'total_amount' => $loans->sum('amount'),
            'pending_amount' => $loans->where('status', 'pending')->sum('amount'),
            'approved_amount' => $loans->where('status', 'approved')->sum('amount'),
            'disbursed_amount' => $loans->where('status', 'disbursed')->sum('amount'),
            'active_amount' => $loans->where('status', 'active')->sum('amount'),
        ];

        return view('loans.print-all', compact('loans', 'stats'));
    }

    public function printSingle(Loan $loan)
    {
        $loan->load(['client', 'loanProduct', 'repayments', 'reschedules', 'collaterals', 'guarantors', 'creator']);

        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = max(0, $loan->total_repayment - $totalPaid);
        $nextDueDate = $this->calculateNextDueDate($loan);
        $daysOverdue = $this->calculateDaysOverdue($loan);

        // Calculate loan performance metrics
        $performance = $this->calculateLoanPerformance($loan);

        return view('loans.print-single', compact('loan', 'totalPaid', 'remainingBalance', 'nextDueDate', 'daysOverdue', 'performance'));
    }

    /**
     * Download all loans report as PDF with filters applied
     */
    public function downloadAll(Request $request)
    {
        $query = Loan::with(['client', 'loanProduct', 'collaterals', 'guarantors'])
            ->orderBy('created_at', 'desc');

        // Apply same filters as index method
        if ($search = $request->search) {
            $query->where(function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhere('purpose', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('client_number', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                  });
            });
        }

        $query->when($request->status, fn($q) => $q->where('status', $request->status))
              ->when($request->loan_type, fn($q) => $q->where('loan_type', $request->loan_type))
              ->when($request->start_date, fn($q) => $q->whereDate('application_date', '>=', $request->start_date))
              ->when($request->end_date, fn($q) => $q->whereDate('application_date', '<=', $request->end_date));

        $loans = $query->get();

        // Calculate stats for filtered loans
        $stats = [
            'total' => $loans->count(),
            'pending' => $loans->where('status', 'pending')->count(),
            'approved' => $loans->where('status', 'approved')->count(),
            'disbursed' => $loans->where('status', 'disbursed')->count(),
            'rejected' => $loans->where('status', 'rejected')->count(),
            'active' => $loans->where('status', 'active')->count(),
            'completed' => $loans->where('status', 'completed')->count(),
            'paused' => $loans->where('status', 'paused')->count(),
            'closed' => $loans->where('status', 'closed')->count(),
            'total_amount' => $loans->sum('amount'),
            'pending_amount' => $loans->where('status', 'pending')->sum('amount'),
            'approved_amount' => $loans->where('status', 'approved')->sum('amount'),
            'disbursed_amount' => $loans->where('status', 'disbursed')->sum('amount'),
            'active_amount' => $loans->where('status', 'active')->sum('amount'),
        ];

        $pdf = PDF::loadView('loans.print-all', compact('loans', 'stats'));
        $filename = 'loans-report-' . now()->format('Y-m-d-H-i-s') . '.pdf';

        return $pdf->download($filename);
    }

    /**
     * Download single loan details as PDF
     */
    public function downloadSingle(Loan $loan)
    {
        $loan->load(['client', 'loanProduct', 'repayments', 'reschedules', 'collaterals', 'guarantors', 'creator']);

        $totalPaid = $loan->repayments->sum('amount');
        $remainingBalance = max(0, $loan->total_repayment - $totalPaid);
        $nextDueDate = $this->calculateNextDueDate($loan);
        $daysOverdue = $this->calculateDaysOverdue($loan);

        // Calculate loan performance metrics
        $performance = $this->calculateLoanPerformance($loan);

        $pdf = \PDF::loadView('loans.print-single', compact('loan', 'totalPaid', 'remainingBalance', 'nextDueDate', 'daysOverdue', 'performance'));
        $filename = 'loan-' . $loan->loan_number . '-' . now()->format('Y-m-d') . '.pdf';

        return $pdf->download($filename);
    }

    /**
     * Export pending loans as CSV
     */
    public function exportPendingCsv(Request $request)
    {
        $query = Loan::with(['client', 'loanProduct'])
            ->where('status', 'pending')
            ->orderBy('created_at', 'desc');

        if ($request->has('search') && $request->search != '') {
            $search = $request->search;
            $query->where(function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhere('purpose', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('client_number', 'like', "%{$search}%");
                  });
            });
        }

        $loans = $query->get();

        $filename = 'pending-loans-' . now()->format('Y-m-d-H-i-s') . '.csv';

        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename=\"$filename\"",
        ];

        $callback = function() use ($loans) {
            $file = fopen('php://output', 'w');

            // CSV headers
            fputcsv($file, [
                'Loan Number',
                'Client Name',
                'Client Number',
                'Amount',
                'Interest Rate (%)',
                'Duration (Months)',
                'Loan Type',
                'Purpose',
                'Application Date',
                'Monthly Payment',
                'Total Repayment',
                'Status'
            ]);

            // CSV data
            foreach ($loans as $loan) {
                fputcsv($file, [
                    $loan->loan_number,
                    $loan->client ? $loan->client->first_name . ' ' . $loan->client->last_name : '',
                    $loan->client ? $loan->client->client_number : '',
                    number_format($loan->amount, 2),
                    $loan->interest_rate,
                    $loan->duration_months,
                    ucfirst($loan->loan_type),
                    $loan->purpose,
                    $loan->application_date ? $loan->application_date->format('Y-m-d') : '',
                    number_format($loan->monthly_payment, 2),
                    number_format($loan->total_repayment, 2),
                    ucfirst($loan->status)
                ]);
            }

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Export pending loans as PDF
     */
    public function exportPendingPdf(Request $request)
    {
        $query = Loan::with(['client', 'loanProduct'])
            ->where('status', 'pending')
            ->orderBy('created_at', 'desc');

        if ($request->has('search') && $request->search != '') {
            $search = $request->search;
            $query->where(function($q) use ($search) {
                $q->where('loan_number', 'like', "%{$search}%")
                  ->orWhere('purpose', 'like', "%{$search}%")
                  ->orWhereHas('client', function($q) use ($search) {
                      $q->where('first_name', 'like', "%{$search}%")
                        ->orWhere('last_name', 'like', "%{$search}%")
                        ->orWhere('client_number', 'like', "%{$search}%");
                  });
            });
        }

        $loans = $query->get();

        $stats = [
            'total' => $loans->count(),
            'total_amount' => $loans->sum('amount'),
        ];

        $pdf = PDF::loadView('loans.pending-pdf', compact('loans', 'stats'));
        $filename = 'pending-loans-' . now()->format('Y-m-d-H-i-s') . '.pdf';

        return $pdf->download($filename);
    }
}
