<?php

namespace App\Http\Controllers\Partner;

use App\Http\Controllers\Controller;
use App\Models\SavingsCollection;
use App\Models\Saving;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Carbon\Carbon;

class SavingsCollectionController extends Controller
{
    public function index()
    {
        $partnerId = auth()->user()->partner_id;
        $collections = SavingsCollection::where('partner_id', $partnerId)
            ->with(['savingsAccount', 'customer'])
            ->latest()
            ->paginate(15);
        return view('partner.savings-collections.index', compact('collections'));
    }

    public function create()
    {
        $partnerId = auth()->user()->partner_id;
        
        // Only RD type savings need collections
        $savings = Saving::where('partner_id', $partnerId)
            ->where('status', 'active')
            ->where('savings_type', 'RD')
            ->whereNotNull('monthly_deposit')
            ->whereNotNull('duration_value')
            ->with(['customer', 'savingsScheme'])
            ->get()
            ->filter(function($saving) {
                // Only show RD accounts that haven't completed all installments
                return $saving->collected_months < $saving->duration_value;
            });
        
        return view('partner.savings-collections.create', compact('savings'));
    }

    public function getSchedule($savingId)
    {
        $saving = Saving::findOrFail($savingId);
        $this->ensurePartnerOwnership($saving);
        
        // Only RD accounts have schedules
        if ($saving->savings_type !== 'RD') {
            return response()->json([
                'error' => 'Only RD accounts have collection schedules'
            ], 400);
        }
        
        $schedule = $this->generateSchedule($saving);
        
        return response()->json([
            'schedule' => $schedule,
            'saving' => [
                'id' => $saving->id,
                'savings_number' => $saving->savings_number,
                'savings_type' => $saving->savings_type,
                'monthly_deposit' => $saving->monthly_deposit,
                'collected_months' => $saving->collected_months,
                'total_months' => $saving->duration_value,
                'remaining_months' => $saving->remaining_months,
            ]
        ]);
    }

    private function generateSchedule(Saving $saving)
    {
        $saving->load(['collections' => function($query) {
            $query->orderBy('collection_date', 'asc');
        }]);
        
        $schedule = [];
        $installmentAmount = $saving->installment_amount;
        $durationValue = $saving->duration_value;
        $durationType = $saving->duration_type;
        $depositDate = $saving->deposit_date;
        $targetAmount = $saving->target_amount;
        
        $collections = $saving->collections;
        $allocatedCollections = [];
        $remainingBalance = $targetAmount;
        $totalCollectedSoFar = 0;
        
        for ($i = 1; $i <= $durationValue; $i++) {
            $dueDate = match($durationType) {
                'daily' => $depositDate->copy()->addDays($i),
                'weekly' => $depositDate->copy()->addWeeks($i),
                'monthly' => $depositDate->copy()->addMonths($i),
            };
            
            $installmentDue = ($i === $durationValue) 
                ? round($remainingBalance, 2)
                : round(min($installmentAmount, $remainingBalance), 2);
            
            $collectedDate = null;
            $collectedAmount = 0;
            $status = 'pending';
            
            $periodStart = ($i === 1) 
                ? $depositDate->copy()->subDay()
                : match($durationType) {
                    'daily' => $depositDate->copy()->addDays($i - 1),
                    'weekly' => $depositDate->copy()->addWeeks($i - 1),
                    'monthly' => $depositDate->copy()->addMonths($i - 1),
                };
            
            $periodEnd = $dueDate->copy()->addDays(30);
            
            $matchingCollection = $collections->first(function($col) use ($periodStart, $periodEnd, $allocatedCollections) {
                return !in_array($col->id, $allocatedCollections) && 
                       $col->collection_date->between($periodStart, $periodEnd);
            });
            
            if ($matchingCollection) {
                $collectedDate = $matchingCollection->collection_date;
                $collectedAmount = $matchingCollection->amount;
                $allocatedCollections[] = $matchingCollection->id;
                $totalCollectedSoFar += $collectedAmount;
                
                if ($collectedDate->lte($dueDate)) {
                    $status = 'collected';
                } else {
                    $status = 'overdue';
                }
            } else {
                if ($dueDate->isPast()) {
                    $expectedCollected = $installmentAmount * ($i - 1);
                    if ($totalCollectedSoFar < $expectedCollected + $installmentDue) {
                        $status = 'overdue';
                    }
                }
            }
            
            if ($collectedAmount > 0) {
                $remainingBalance = max(0, $remainingBalance - $collectedAmount);
            } else {
                $remainingBalance = max(0, $remainingBalance - $installmentDue);
            }
            
            $schedule[] = [
                'installment_number' => $i,
                'due_date' => $dueDate->format('Y-m-d'),
                'due_amount' => $installmentDue,
                'collected_date' => $collectedDate ? $collectedDate->format('Y-m-d') : null,
                'collected_amount' => round($collectedAmount, 2),
                'status' => $status,
                'remaining_balance' => round($remainingBalance, 2),
            ];
        }
        
        return $schedule;
    }

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

        $saving = Saving::findOrFail($validated['saving_id']);
        $this->ensurePartnerOwnership($saving);

        // RULE 1: Only RD accounts allow collections
        if ($saving->savings_type !== 'RD') {
            return back()->withErrors([
                'saving_id' => 'Only RD (Recurring Deposit) accounts allow collections. ' .
                              ($saving->savings_type === 'FD' ? 'FD accounts are created with a one-time lump sum deposit.' : 
                              'MIS accounts are created with a one-time deposit and only provide payouts.')
            ])->withInput();
        }

        // RULE 2: Account must be active
        if ($saving->status !== 'active') {
            return back()->withErrors([
                'saving_id' => 'Cannot collect from ' . strtoupper($saving->status) . ' accounts. Account status: ' . ucfirst($saving->status)
            ])->withInput();
        }

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

        // RULE 3: Check if amount exceeds remaining
        if ($amount > $remaining) {
            return back()->withErrors([
                'amount' => 'Collection amount (₹' . number_format($amount, 2) . ') cannot exceed remaining amount (₹' . number_format($remaining, 2) . ')'
            ])->withInput();
        }

        // RULE 4: Check if all installments are already collected
        if ($saving->collected_months >= $saving->duration_value) {
            return back()->withErrors([
                'saving_id' => 'All installments have been collected for this RD account. Account should be matured.'
            ])->withInput();
        }

        $collectionDate = Carbon::parse($validated['collection_date']);
        
        $partner = auth()->user()->partner;
        
        $collection = SavingsCollection::create([
            'partner_id' => $partnerId,
            'saving_id' => $saving->id,
            'customer_id' => $saving->customer_id,
            'collection_number' => $partner->generateCollectionNumber(),
            'amount' => $amount,
            'collection_date' => $collectionDate,
            'due_date' => $collectionDate, // Can be set from schedule
            'payment_method' => $validated['payment_method'],
            'reference_number' => $validated['reference_number'] ?? null,
            'notes' => $validated['notes'] ?? null,
        ]);

        // Update saving
        $saving->collected_amount += $amount;
        
        // Auto-mature if target reached
        if ($saving->collected_amount >= $saving->target_amount) {
            $saving->status = 'matured';
            $successMessage = 'RD collection recorded successfully! Account has reached maturity (₹' . number_format($saving->collected_amount, 2) . ').';
        } else {
            $remaining = $saving->target_amount - $saving->collected_amount;
            $successMessage = 'RD collection of ₹' . number_format($amount, 2) . ' recorded successfully! Remaining: ₹' . number_format($remaining, 2);
        }
        
        $saving->save();

        return redirect()->route('partner.savings-collections.index')->with('success', $successMessage);
    }

    public function show(SavingsCollection $savingsCollection)
    {
        $this->ensurePartnerOwnership($savingsCollection);
        $savingsCollection->load(['savingsAccount', 'customer']);
        return view('partner.savings-collections.show', compact('savingsCollection'));
    }

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