<?php

namespace App\Http\Controllers\Partner;

use App\Http\Controllers\Controller;
use App\Models\Repayment;
use App\Models\Loan;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Carbon\Carbon;

class RepaymentController extends Controller
{
    public function index()
    {
        $partnerId = auth()->user()->partner_id;
        $repayments = Repayment::where('partner_id', $partnerId)
            ->with(['loan', 'customer'])
            ->latest()
            ->paginate(15);
        return view('partner.repayments.index', compact('repayments'));
    }

    public function create()
    {
        $partnerId = auth()->user()->partner_id;
        $loans = Loan::where('partner_id', $partnerId)
            ->where('status', 'active')
            ->where('remaining_amount', '>', 0)
            ->with(['customer', 'loanScheme', 'scheme'])
            ->get();
        return view('partner.repayments.create', compact('loans'));
    }

    public function getSchedule($loanId)
    {
        $loan = Loan::findOrFail($loanId);
        $this->ensurePartnerOwnership($loan);
        
        $schedule = $this->generateSchedule($loan);
        
        return response()->json([
            'schedule' => $schedule,
            'loan' => [
                'id' => $loan->id,
                'loan_number' => $loan->loan_number,
                'remaining_amount' => $loan->remaining_amount,
                'monthly_installment' => $loan->monthly_installment,
            ]
        ]);
    }

    private function generateSchedule(Loan $loan)
    {
        $loan->load(['repayments' => function($query) {
            $query->orderBy('payment_date', 'asc');
        }]);
        
        $schedule = [];
        $installmentAmount = $loan->monthly_installment;
        $durationValue = $loan->duration_value;
        $durationType = $loan->duration_type;
        $disbursementDate = $loan->disbursement_date;
        $totalLoanAmount = $loan->total_amount;
        
        $repayments = $loan->repayments;
        $allocatedRepayments = [];
        $remainingBalance = $totalLoanAmount;
        $totalPaidSoFar = 0;
        
        for ($i = 1; $i <= $durationValue; $i++) {
            $dueDate = match($durationType) {
                'daily' => $disbursementDate->copy()->addDays($i),
                'weekly' => $disbursementDate->copy()->addWeeks($i),
                'monthly' => $disbursementDate->copy()->addMonths($i),
            };
            
            $installmentDue = ($i === $durationValue) 
                ? round($remainingBalance, 2)
                : round(min($installmentAmount, $remainingBalance), 2);
            
            $paidDate = null;
            $paidAmount = 0;
            $status = 'pending';
            
            $periodStart = ($i === 1) 
                ? $disbursementDate->copy()->subDay()
                : match($durationType) {
                    'daily' => $disbursementDate->copy()->addDays($i - 1),
                    'weekly' => $disbursementDate->copy()->addWeeks($i - 1),
                    'monthly' => $disbursementDate->copy()->addMonths($i - 1),
                };
            
            $periodEnd = $dueDate->copy()->addDays(30);
            
            $matchingRepayment = $repayments->first(function($rep) use ($periodStart, $periodEnd, $allocatedRepayments) {
                return !in_array($rep->id, $allocatedRepayments) && 
                       $rep->payment_date->between($periodStart, $periodEnd);
            });
            
            if ($matchingRepayment) {
                $paidDate = $matchingRepayment->payment_date;
                $paidAmount = $matchingRepayment->amount;
                $allocatedRepayments[] = $matchingRepayment->id;
                $totalPaidSoFar += $paidAmount;
                
                if ($paidDate->lte($dueDate)) {
                    $status = 'paid';
                } else {
                    $status = 'overdue';
                }
            } else {
                if ($dueDate->isPast()) {
                    $expectedPaid = $installmentAmount * ($i - 1);
                    if ($totalPaidSoFar < $expectedPaid + $installmentDue) {
                        $status = 'overdue';
                    }
                }
            }
            
            if ($paidAmount > 0) {
                $remainingBalance = max(0, $remainingBalance - $paidAmount);
            } else {
                $remainingBalance = max(0, $remainingBalance - $installmentDue);
            }
            
            $schedule[] = [
                'installment_number' => $i,
                'due_date' => $dueDate->format('Y-m-d'),
                'due_amount' => $installmentDue,
                'paid_date' => $paidDate ? $paidDate->format('Y-m-d') : null,
                'paid_amount' => round($paidAmount, 2),
                'status' => $status,
                'remaining_balance' => round($remainingBalance, 2),
            ];
        }
        
        return $schedule;
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'loan_id' => 'required|exists:loans,id',
            'amount' => 'required|numeric|min:1',
            'payment_date' => 'required|date',
            'payment_method' => 'required|in:cash,bank_transfer,cheque,other',
            'reference_number' => 'nullable|string|max:255',
            'notes' => 'nullable|string',
        ]);

        $loan = Loan::findOrFail($validated['loan_id']);
        $this->ensurePartnerOwnership($loan);

        $partnerId = auth()->user()->partner_id;
        $amount = $validated['amount'];
        $remaining = $loan->remaining_amount;

        // Calculate principal and interest portions
        $principalPortion = min($amount, $remaining);
        $interestPortion = 0;
        $penaltyPortion = 0;

        // Check for overdue penalties
        $penalties = $loan->penalties()->where('status', 'pending')->sum('amount');
        if ($penalties > 0 && $amount > $principalPortion) {
            $penaltyPortion = min($penalties, $amount - $principalPortion);
            $remainingAfterPenalty = $amount - $principalPortion - $penaltyPortion;
            $interestPortion = max(0, $remainingAfterPenalty);
        } else {
            $interestPortion = max(0, $amount - $principalPortion);
        }

        $paymentDate = Carbon::parse($validated['payment_date']);
        $dueDate = $loan->due_date;
        $status = $paymentDate->gt($dueDate) ? 'overdue' : 'on_time';

        $repayment = Repayment::create([
            'partner_id' => $partnerId,
            'loan_id' => $loan->id,
            'customer_id' => $loan->customer_id,
            'repayment_number' => 'REP-' . strtoupper(Str::random(10)),
            'amount' => $amount,
            'principal_amount' => $principalPortion,
            'interest_amount' => $interestPortion,
            'penalty_amount' => $penaltyPortion,
            'payment_date' => $paymentDate,
            'due_date' => $dueDate,
            'status' => $status,
            'payment_method' => $validated['payment_method'],
            'reference_number' => $validated['reference_number'] ?? null,
            'notes' => $validated['notes'] ?? null,
        ]);

        // Update loan
        $loan->paid_amount += $principalPortion;
        $loan->remaining_amount -= $principalPortion;
        if ($loan->remaining_amount <= 0) {
            $loan->status = 'completed';
        }
        $loan->save();

        // Update penalties if paid
        if ($penaltyPortion > 0) {
            $loan->penalties()->where('status', 'pending')
                ->orderBy('penalty_date')
                ->get()
                ->each(function ($penalty) use (&$penaltyPortion) {
                    if ($penaltyPortion > 0) {
                        $paid = min($penalty->amount, $penaltyPortion);
                        $penalty->amount -= $paid;
                        $penaltyPortion -= $paid;
                        if ($penalty->amount <= 0) {
                            $penalty->status = 'paid';
                            $penalty->amount = 0;
                        }
                        $penalty->save();
                    }
                });
        }

        return redirect()->route('partner.repayments.index')->with('success', 'Repayment recorded successfully.');
    }

    public function show(Repayment $repayment)
    {
        $this->ensurePartnerOwnership($repayment);
        $repayment->load(['loan', 'customer']);
        return view('partner.repayments.show', compact('repayment'));
    }

    private function ensurePartnerOwnership($model)
    {
        if ($model->partner_id !== auth()->user()->partner_id) {
            abort(403);
        }
    }
}
