<?php

namespace App\Http\Controllers;

use App\Http\Requests\LoanApplicationRequest;
use App\Models\Loan;
use App\Models\LoanType;
use App\Models\Account;
use App\Models\Transaction;
use App\Models\IndividualLoanRepayment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class LoanController extends Controller
{
    /**
     * Member loan application form
     */
    public function apply()
    {
        $loanTypes = LoanType::all();

        return view('loans.apply', compact('loanTypes'));
    }

    /**
     * Store member loan application
     */
    public function store(LoanApplicationRequest $request)
    {
        $data = $request->validated();

        $loanType = LoanType::find($data['loan_type_id']);

        if (!$loanType) {
            return back()->withErrors(['loan_type_id' => 'Invalid loan type'])->withInput();
        }

        // Asset financing validation rule
        if (strtolower($loanType->name) === 'asset financing') {
            if (empty($data['asset_value'])) {
                return back()->withErrors(['asset_value' => 'Asset value required'])->withInput();
            }

            $maxAllowed = floatval($data['asset_value']) * 0.5;

            if (floatval($data['amount']) > $maxAllowed) {
                return back()->withErrors([
                    'amount' => "Max allowed is 50% of asset value (UGX " . number_format($maxAllowed) . ")"
                ])->withInput();
            }
        }

        Loan::create([
            'loan_type_id'   => $loanType->id,
            'user_id'        => Auth::id(),
            'principal'      => $data['amount'],
            'interest_rate'  => $loanType->interest_rate ?? 0,
            'total_payable'  => 0,
            'balance'        => 0,
            'term_months'    => $loanType->duration_months ?? 12,
            'asset_value'    => $data['asset_value'] ?? null,
            'purpose'        => $data['purpose'] ?? null,
            'status'         => 'pending',
        ]);

        return redirect()->route('member.loans.index')
            ->with('success', 'Loan application submitted.');
    }

    /**
     * Member loan list
     */
    public function memberLoans()
    {
        $loans = Loan::where('user_id', auth()->id())
            ->with('loanType')
            ->latest()
            ->get();

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

    /**
     * Loan details (admin or member)
     */
    public function show(Loan $loan)
    {
        $user = auth()->user();

        if ($user->role !== 'admin' && $user->id !== $loan->user_id) {
            abort(403);
        }

        // uses the Loan->repayments() relation which must point to IndividualLoanRepayment
        $repayments = $loan->repayments()->orderBy('created_at')->get();

        $view = ($user->role === 'admin') ? 'admin.loans.show' : 'member.loans.show';

        return view($view, compact('loan', 'repayments'));
    }

    /**
     * Admin loan list
     */
    public function adminIndex(Request $request)
    {
        $q = Loan::with('user', 'loanType');

        if ($request->filled('status')) {
            $q->where('status', $request->status);
        }

        $loans = $q->latest()->paginate(20);

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

    /**
     * Admin: Approve loan
     */
    public function approve(Request $request, Loan $loan)
    {
        $this->authorizeAdmin();

        if ($loan->status !== 'pending') {
            return back()->with('error', 'Only pending loans can be approved.');
        }

        $loanType = $loan->loanType;

        // defensive: ensure loanType exists
        if (! $loanType) {
            return back()->with('error', 'Loan type missing for this loan.');
        }

        $principal      = floatval($request->approved_amount ?? $loan->principal);
        $annualRate     = floatval($loanType->interest_rate ?? $loan->interest_rate ?? 0);
        $termMonths     = intval($loan->term_months ?? 12);
        $startDate      = now()->startOfDay();

        $schedule = $this->generateAmortizationSchedule($principal, $annualRate, $termMonths, $startDate);

        $totalPayable = array_sum(array_column($schedule, 'payment'));

        $loan->update([
            'principal'      => $principal,
            'interest_rate'  => $annualRate,
            'total_payable'  => $totalPayable,
            'balance'        => $totalPayable,
            'amortization_schedule' => $schedule,
            'approved_by'    => auth()->id(),
            'approved_at'    => now(),
            'status'         => 'approved',
        ]);

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

    /**
     * Reject loan
     */
    public function reject(Loan $loan)
    {
        $this->authorizeAdmin();

        if (!in_array($loan->status, ['pending', 'approved'])) {
            return back()->with('error', 'Cannot reject.');
        }

        $loan->update(['status' => 'rejected']);

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

    /**
     * Disburse loan
     */
    public function disburse(Request $request, Loan $loan)
    {
        $this->authorizeAdmin();

        if ($loan->status !== 'approved') {
            return back()->with('error', 'Only approved loans can be disbursed.');
        }

        $account = Account::where('user_id', $loan->user_id)->first();
        if ($loan->balance <= 0) {
    return back()->with('error', 'This loan is fully paid and cannot receive more repayments.');
}

if ($request->amount > $loan->balance) {
    return back()->with('error', 'Repayment exceeds outstanding loan balance.');
}



        DB::transaction(function () use ($loan, $account) {

            $loan->update([
                'disbursed_at' => now(),
                'disbursed_by' => auth()->id(),
                'status' => 'active',
            ]);

            if ($account) {
                $before = $account->balance;
                $after  = $before + $loan->principal;

                Transaction::create([
                    'account_id'     => $account->id,
                    'admin_id'       => auth()->id(),
                    'type'           => 'deposit',
                    'amount'         => $loan->principal,
                    'balance_before' => $before,
                    'balance_after'  => $after,
                    'description'    => 'Loan disbursement for loan #' . $loan->id,
                ]);

                $account->update(['balance' => $after]);
            }
        });

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

    /**
     * Record repayment (admin or member)
     */
    public function repay(Request $request, Loan $loan)
    {
        $this->authorizeAdminOrOwner($loan);

        $request->validate([
            'amount'      => 'required|numeric|min:1',
            'account_id'  => 'nullable|exists:accounts,id',
            'reference'   => 'nullable|string|max:100',
            'notes'       => 'nullable|string|max:1000',
        ]);

        DB::transaction(function () use ($request, $loan) {

            $amount = floatval($request->amount);
            if ($amount > $loan->balance) {
    return back()->with('error', 'Repayment exceeds remaining balance.');
}

            $accountId = $request->account_id;

            $balanceBefore = null;
            $balanceAfter  = null;

            // If user provided an account to take funds from, update it & create a Transaction
            if ($accountId) {
                $acct = Account::lockForUpdate()->find($accountId);
                if (! $acct) {
                    throw new \Exception('Account not found.');
                }

                $balanceBefore = $acct->balance ?? 0;
                $acct->balance = ($acct->balance ?? 0) - $amount;
                $acct->save();
                $balanceAfter = $acct->balance;

                Transaction::create([
                    'account_id'     => $acct->id,
                    'admin_id'       => auth()->id(),          // who recorded the repayment
                    'type'           => 'loan_repayment',
                    'amount'         => $amount,
                    'balance_before' => $balanceBefore,
                    'balance_after'  => $balanceAfter,
                    'description'    => 'Loan repayment for loan #' . $loan->id,
                ]);
            }

            // Create the IndividualLoanRepayment record (member_id points to borrower)
            IndividualLoanRepayment::create([
                'loan_id'        => $loan->id,
                'member_id'      => $loan->user_id,
                'admin_id'       => auth()->id(),
                'amount'         => $amount,
                'balance_before' => $balanceBefore,
                'balance_after'  => $balanceAfter,
                'reference'      => $request->reference,
                'notes'          => $request->notes,
                'status'         => 'completed',
            ]);

            // update loan balance (use existing loan->balance, fallback to total_payable)
$currentOutstanding = floatval($loan->balance ?? $loan->total_payable ?? 0);

$newBalance = max(0, $currentOutstanding - $amount);

$loan->balance = $newBalance;

// Only admin manually closes, but system will SUGGEST closure:
if ($newBalance == 0 && $loan->status !== 'closed') {
    $loan->status = 'active';  // stays active until Admin closes
}

$loan->save();

        });

        return back()->with('success', 'Repayment recorded.');
    }




    /**
 * Member-initiated loan repayment
 */

    /**
     * Amortization schedule generator
     */
    protected function generateAmortizationSchedule($principal, $annualRate, $months, Carbon $start)
    {
        $schedule = [];

        $monthlyRate = ($annualRate / 100) / 12;

        if ($monthlyRate <= 0) {
            // simple equal payments
            $payment = round($principal / $months, 2);
            $balance = $principal;

            for ($i = 1; $i <= $months; $i++) {
                $p = ($i == $months) ? $balance : $payment;
                $balance -= $p;

                $schedule[] = [
                    'period'     => $i,
                    'due_date'   => $start->copy()->addMonths($i)->toDateString(),
                    'payment'    => $p,
                    'principal'  => $p,
                    'interest'   => 0,
                    'balance'    => max(0, $balance),
                ];
            }

            return $schedule;
        }

        // annuity formula
        $r = $monthlyRate;
        $n = $months;
        $payment = round($principal * ($r / (1 - pow(1 + $r, -$n))), 2);
        $balance = $principal;

        for ($i = 1; $i <= $n; $i++) {
            $interest = round($balance * $r, 2);
            $principalPaid = round($payment - $interest, 2);

            if ($i == $n) {
                $principalPaid = $balance;
                $payment = $principalPaid + $interest;
            }

            $balance -= $principalPaid;

            $schedule[] = [
                'period'     => $i,
                'due_date'   => $start->copy()->addMonths($i)->toDateString(),
                'payment'    => round($payment, 2),
                'principal'  => $principalPaid,
                'interest'   => $interest,
                'balance'    => max(0, $balance),
            ];
        }

        return $schedule;
    }

    protected function authorizeAdmin()
    {
        if (auth()->user()->role !== 'admin') {
            abort(403);
        }
    }

    protected function authorizeAdminOrOwner(Loan $loan)
    {
        if (auth()->user()->role !== 'admin' && auth()->id() !== $loan->user_id) {
            abort(403);
        }
    }


   public function close(Loan $loan)
{
    $this->authorizeAdmin();

    if ($loan->balance > 0) {
        return back()->with('error', 'Loan still has a remaining balance.');
    }

    $loan->status = 'closed';
    $loan->save();

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

//loan officer view
public function loanOfficerIndex()
{
    $stats = [
        'pending'  => Loan::where('status', 'pending')->count(),
        'approved' => Loan::where('status', 'approved')->count(),
        'active'   => Loan::where('status', 'active')->count(),
    ];

    $loans = Loan::with('user', 'loanType')
        ->whereIn('status', ['pending', 'approved'])
        ->latest()
        ->get();

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


}
