<?php

namespace App\Http\Controllers;

use App\Models\Application;
use App\Models\Customer;
use App\Models\DisbursedLoan;
use App\Models\LoanType;
use App\Models\PaymentSchedule;
use App\Models\Repayment;
use App\Models\JournalEntry;
use App\Models\JournalEntryItem;
use App\Models\GeneralLedgerEntry;
use App\Models\CashBankAccount;
use App\Models\FinancialYear;
use App\Models\Currency;
use App\Services\MobileMoneyService;
use App\Services\LipilaPaymentService;
use App\Services\SmsService;
use App\Services\CreditScoreService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\URL;
use Carbon\Carbon;

class CustomerDashboardController extends Controller
{
    private $smsService;
    private $paymentService;
    private $creditScoreService;

    public function __construct(SmsService $smsService, LipilaPaymentService $paymentService, CreditScoreService $creditScoreService)
    {
        $this->smsService = $smsService;
        $this->paymentService = $paymentService;
        $this->creditScoreService = $creditScoreService;
    }

    /**
     * Show customer dashboard
     */
      public function index()
{
    $customer = Auth::guard('customer')->user();
    
    // 1. Fetch Applications and Stats
    $applications = $customer->applications()->latest()->get();
    $applicationStats = [
        'total' => $applications->count(),
        'approved' => $applications->where('status', 'approved')->count(),
        'pending' => $applications->whereIn('status', ['submitted', 'under_review'])->count(),
        'rejected' => $applications->where('status', 'rejected')->count(),
    ];

    $activeApplications = $applications->whereIn('status', ['submitted', 'under_review', 'approved']);
    $recentApplications = $applications->take(5);

    // 2. Process Application Progress
    $applicationProgress = [];
    foreach ($activeApplications as $application) {
        $applicationProgress[$application->id] = [
            'application' => $application,
            'progress' => $this->calculateApplicationProgress($application),
            'status_color' => $this->getStatusColor($application->status),
            'status_text' => $this->getStatusText($application->status),
        ];
    }

    // 3. Next Installment
    $nextInstallment = \App\Models\PaymentSchedule::where('customerid', $customer->id)
        ->where('status', '!=', 'paid')
        ->where('paymentdate', '>=', now()->startOfDay())
        ->orderBy('paymentdate', 'asc')
        ->first();

    // 4. Unified Transaction History (The New Addition)
    $disbursements = $customer->disbursements()->latest()->take(5)->get();
    $repayments = $customer->repayments()->latest()->take(5)->get();

    $allTransactions = collect()
        ->concat($disbursements->map(function($d) {
            $d->tx_type = 'Disbursement';
            $d->tx_date = $d->disburseddate ? \Carbon\Carbon::parse($d->disburseddate) : $d->created_at;
            $d->display_amount = -abs((float)$d->amount);
            $d->ref = $d->loannumber;
            return $d;
        }))
        ->concat($repayments->map(function($r) {
            $r->tx_type = 'Repayment';
            $r->tx_date = \Carbon\Carbon::parse($r->payment_date);
            $r->display_amount = abs((float)$r->amount_paid);
            $r->ref = $r->receipt_number ?? $r->loannumber;
            return $r;
        }))
        ->sortByDesc('tx_date')
        ->take(5);

    $loanStats = $customer->getLoanStats();
    $creditScoreInfo = $this->getCreditScoreInfo($customer);

    return view('customer.dashboard', compact(
        'customer', 'applications', 'applicationStats', 'activeApplications',
        'recentApplications', 'applicationProgress', 'loanStats', 
        'creditScoreInfo', 'nextInstallment', 'allTransactions'
    ));
}
    /**
     * STEP 1: Show Payment Method Selection
     */
    public function showMethodSelection(Request $request)
    {
        $customer = Auth::guard('customer')->user();
        $loanStats = $customer->getLoanStats();
        $selectedAmount = $request->query('amount', $loanStats['total_next_due_amount']);
        $activeApplications = $customer->applications()->whereIn('status', ['submitted', 'under_review', 'approved'])->get();

        return view('customer.payment_method', compact('customer', 'loanStats', 'activeApplications', 'selectedAmount'));
    }

    /**
     * STEP 2: Show Payment Details (Midnight Indigo View)
     */
    public function showPaymentDetails(Request $request)
    {
        $customer = Auth::guard('customer')->user();
        $method = $request->input('provider');
        $amount = $request->input('amount');
        $loanStats = $customer->getLoanStats();
        $activeApplications = $customer->applications()->whereIn('status', ['submitted', 'under_review', 'approved'])->get();
        
        $activeLoan = $customer->activeDisbursedLoans()->first();
        $loanNumber = $activeLoan ? $activeLoan->loannumber : 'REPAYMENT';

        return view('customer.payment_details', compact('customer', 'method', 'amount', 'loanStats', 'activeApplications', 'loanNumber'));
    }

    /**
     * STEP 3: Process Payment (Trigger Lipila STK Push)
     */
      /**
 * STEP 3: Process Payment (Trigger Lipila STK Push)
 */
public function processPayment(Request $request)
{
    $validated = $request->validate([
        'amount' => 'required|numeric|min:1',
        'phone_number' => 'required|string',
        'provider' => 'required|string',
        'loan_number' => 'required|string',
    ]);

    $customer = Auth::guard('customer')->user();
    $loan = DB::table('disbursedloans')->where('loannumber', $validated['loan_number'])->first();

    if (!$loan) return back()->with('error', 'Loan record not found.');

    try {
        $webhookUrl = URL::to('/api/webhooks/lipila/collection');
        $lipilaData = [
            'amount' => $validated['amount'],
            'account_number' => $validated['phone_number'],
            'paymentmethod' => strtolower($validated['provider']),
            'narration' => "Portal Repayment: " . $validated['loan_number'],
            'currency' => 'ZMW',
            'callback_url' => $webhookUrl,
        ];

        $response = $this->paymentService->collect($lipilaData, $loan->companyid, 1);

        if ($response && $response->successful()) {
            
            $responseData = $response->json();
            
            // Log for debugging
            Log::info('Gateway Response for DB Insert:', $responseData);

            // FIX: Map 'account_number' and provide 'identifier' to satisfy DB constraints
            DB::table('payment_collections')->insert([
                'company_id'       => $loan->companyid,
                'created_by'       => 1, // System user or Admin ID
                'loan_id'          => $loan->loanid,
                'loan_customer_id' => $customer->id,
                'account_number'   => $validated['phone_number'], // FIXED: This satisfies the NOT NULL constraint
                'reference_id'     => $responseData['referenceId'] ?? null,
                'identifier'       => $responseData['identifier'] ?? ($responseData['referenceId'] ?? null),
                'amount'           => $validated['amount'],
                'status'           => $responseData['status'] ?? 'Pending',
                'payment_type'     => $validated['provider'],
                'created_at'       => now(),
                'updated_at'       => now(),
            ]);

            // Return JSON for the frontend JavaScript poller
            return response()->json([
                'success' => true,
                'referenceId' => $responseData['referenceId']
            ]);
        }

        return response()->json(['success' => false, 'message' => 'Gateway Error: Could not initiate payment.'], 400);

    } catch (\Exception $e) {
        Log::error('Collection Failed: ' . $e->getMessage());
        return response()->json(['success' => false, 'message' => 'System Error: ' . $e->getMessage()], 500);
    }
}

    /**
     * STEP 4: Check Status (Polling endpoint)
     */
    public function checkPaymentStatusPublic($referenceId): JsonResponse
    {
        $payment = DB::table('payment_collections')->where('reference_id', $referenceId)->first();

        if (!$payment) return response()->json(['success' => false, 'message' => 'Record not found'], 404);

        // If Webhook already marked it successful but accounting isn't done, 
        // this is where you'd trigger Phase 5 if not handled by webhook.
        return response()->json([
            'success' => true,
            'data' => [
                'reference_id' => $payment->reference_id,
                'status' => $payment->status,
                'amount' => (float)$payment->amount
            ]
        ]);
    }

    // ==============================================================================
    // ACCOUNTING CORE (The "Heavy Lifting" Methods)
    // ==============================================================================

    private function calculateAutoAllocation($loan, $paymentAmount)
    {
        $allocations = ['principal' => 0, 'interest' => 0, 'processing' => 0, 'penalty' => 0];
        $remaining = $paymentAmount;
        $priorityOrder = [
            'penalty' => (float) $loan->penalty_balance,
            'processing' => (float) $loan->processing_fee_balance,
            'interest' => (float) $loan->interestbalance,
            'principal' => (float) $loan->principalbalance,
        ];
        foreach ($priorityOrder as $type => $balance) {
            if ($remaining <= 0) break;
            $allocations[$type] = min($balance, $remaining);
            $remaining -= $allocations[$type];
        }
        return $allocations;
    }

    private function updateLoanBalances($loan, $allocations)
    {
        $loan->principalbalance = max(0, bcsub($loan->principalbalance, $allocations['principal'], 2));
        $loan->interestbalance = max(0, bcsub($loan->interestbalance, $allocations['interest'], 2));
        $loan->totalpaid = bcadd($loan->totalpaid, array_sum($allocations), 2);
        $loan->totalbalance = bcadd(bcadd($loan->principalbalance, $loan->interestbalance, 2), bcadd($loan->processing_fee_balance, $loan->penalty_balance, 2), 2);
        $loan->save();
    }

    private function updatePaymentSchedules($loan, $allocations, $paymentDate)
    {
        // Logic to iterate through schedules and mark as 'paid' or 'partial'
        // based on principal/interest/processing allocations.
        $schedules = $loan->paymentSchedules()->where('status', '!=', 'paid')->orderBy('paymentdate', 'asc')->get();
        // ... (Schedule loop logic from RepaymentController)
    }

    // ==============================================================================
    // HELPERS
    // ==============================================================================

    private function calculateApplicationProgress($application): int
    {
        $statusWeights = ['draft' => 25, 'submitted' => 50, 'under_review' => 75, 'approved' => 90, 'disbursed' => 100];
        return $statusWeights[$application->status] ?? 0;
    }

    private function getStatusColor($status): string
    {
        $colors = ['draft' => 'gray', 'submitted' => 'blue', 'under_review' => 'yellow', 'approved' => 'green', 'disbursed' => 'purple'];
        return $colors[$status] ?? 'gray';
    }

    private function getStatusText($status): string
    {
        return ucfirst(str_replace('_', ' ', $status));
    }

    private function getCreditScoreInfo(Customer $customer): array
    {
        $currentScore = $customer->currentCreditScore;
        return [
            'current_score' => $currentScore->credit_score ?? 300,
            'score_band' => $currentScore->score_band ?? 'N/A',
            'risk_level' => $currentScore->risk_level ?? 'Unknown',
            'repayment_rate' => $currentScore->on_time_repayment_rate ?? 0,
            'has_good_credit' => ($currentScore->credit_score ?? 0) >= 600
        ];
    }
    
    /**
 * Show the customer profile and settings
 */
public function profile()
{
    $customer = Auth::guard('customer')->user();

    // Transactions - Unified Collection
    $disbursements = $customer->disbursements()->latest()->get();
    $repayments = $customer->repayments()->latest()->get();

    $allTransactions = collect()
        ->concat($disbursements->map(function($d) {
            $d->tx_type = 'Disbursement';
            $d->tx_date = $d->disburseddate;
            $d->tx_amount = $d->amount;
            return $d;
        }))
        ->concat($repayments->map(function($r) {
            $r->tx_type = 'Repayment';
            $r->tx_date = \Carbon\Carbon::parse($r->payment_date);
            $r->tx_amount = $r->amount_paid;
            return $r;
        }))
        ->sortByDesc('tx_date');

    // Messages - Unified Collection
    $allMessages = $customer->messages()->latest()->get();

    // Stats for sidebar consistency
    $loanStats = $customer->getLoanStats();
    $activeApplications = $customer->applications()
        ->whereIn('status', ['submitted', 'under_review', 'approved'])
        ->get();

    return view('customer.profile', compact(
        'customer', 
        'allTransactions', 
        'allMessages', 
        'loanStats', 
        'activeApplications'
    ));
}


/**
 * Show unified transaction history with running balance
 */
public function transactionsHistory(Request $request)
{
    $customer = Auth::guard('customer')->user();
    $search = $request->query('search');
    $startDate = $request->query('start_date');
    $endDate = $request->query('end_date');

    // 1. Fetch Disbursements with filters
    $disbursementsQuery = $customer->disbursements();
    if ($search) {
        $disbursementsQuery->where('loannumber', 'LIKE', "%{$search}%");
    }
    if ($startDate && $endDate) {
        $disbursementsQuery->whereBetween('disburseddate', [$startDate, $endDate]);
    }
    $disbursements = $disbursementsQuery->latest()->get();

    // 2. Fetch Repayments with filters
    $repaymentsQuery = $customer->repayments();
    if ($search) {
        $repaymentsQuery->where('receipt_number', 'LIKE', "%{$search}%")
                        ->orWhere('loannumber', 'LIKE', "%{$search}%");
    }
    if ($startDate && $endDate) {
        $repaymentsQuery->whereBetween('payment_date', [$startDate, $endDate]);
    }
    $repayments = $repaymentsQuery->latest()->get();

    // 3. Unify and Map
    $allTransactions = collect()
        ->concat($disbursements->map(function($d) {
            $d->tx_type = 'Disbursement';
            $d->tx_date = $d->disburseddate ? \Carbon\Carbon::parse($d->disburseddate) : $d->created_at;
            $d->display_amount = -abs((float)$d->amount);
            return $d;
        }))
        ->concat($repayments->map(function($r) {
            $r->tx_type = 'Repayment';
            $r->tx_date = \Carbon\Carbon::parse($r->payment_date);
            $r->display_amount = abs((float)$r->amount_paid);
            return $r;
        }))
        ->sortByDesc('tx_date');

    // Stats for sidebar
    $loanStats = $customer->getLoanStats();
    $activeApplications = $customer->activeApplications()->get();

    return view('customer.transactions.history', compact(
        'customer', 'allTransactions', 'loanStats', 'activeApplications', 'search', 'startDate', 'endDate'
    ));
}

/**
 * Display active loans for the logged-in customer
 */
public function myLoans()
{
    $customer = Auth::guard('customer')->user();

    // Fetch active loans specifically for this customer
    // We use the same 'active' status logic as the Admin controller
    $loans = \App\Models\DisbursedLoan::where('customerid', $customer->id)
        ->where('status', 'active')
        ->with(['loanType']) // Customer is already known, just load the product type
        ->orderBy('disburseddate', 'desc')
        ->paginate(10); // Standard pagination

    // Calculate dynamic stats for the top cards as requested by the view
    $loanStats = [
        'total_principal' => $loans->sum('amount'),
        'total_balance' => $loans->sum('principalbalance'),
        'total_interest' => $loans->sum('interestbalance'),
        'total_processing' => $loans->sum('processing_fee_balance'),
        'active_loans_count' => $loans->total()
    ];

    // Sidebar requirement: Active applications for the notification badge
    $activeApplications = $customer->applications()
        ->whereNotIn('status', ['draft', 'rejected'])
        ->get();

    return view('customer.loans.index', compact('customer', 'loans', 'loanStats', 'activeApplications'));
}

/**
 * Update the customer's profile photo
 */
public function updatePhoto(Request $request)
{
    $request->validate([
        'profile_photo' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
    ]);

    $customer = Auth::guard('customer')->user();

    if ($request->hasFile('profile_photo')) {
        try {
            // 1. Delete old photo if it exists to keep storage clean
            if ($customer->docpath && \Storage::disk('public')->exists($customer->docpath)) {
                \Storage::disk('public')->delete($customer->docpath);
            }

            // 2. Store the new photo in a 'profile-pictures' directory
            $fileName = 'profile_' . $customer->id . '_' . time() . '.' . $request->file('profile_photo')->getClientOriginalExtension();
            $path = $request->file('profile_photo')->storeAs('profile-pictures', $fileName, 'public');
            
            // 3. Update the 'docpath' column in the database
            // Note: Using DB table directly to ensure it matches your SQL structure
            \DB::table('customer')->where('id', $customer->id)->update([
                'docpath' => $path,
                'updated_at' => now()
            ]);

            return back()->with('success', 'Profile photo updated successfully!');
        } catch (\Exception $e) {
            return back()->with('error', 'Failed to upload photo: ' . $e->getMessage());
        }
    }

    return back()->with('error', 'Please select a valid image file.');
}

}