<?php

namespace App\Http\Controllers\Membership\Member;

use App\Http\Controllers\Controller;
use App\Models\Member;
use App\Models\LoanProduct;
use App\Models\LoanApplication;
use App\Services\LoanService;
use Illuminate\Http\Request;

class LoanApplicationController extends Controller
{
    protected LoanService $loanService;

    public function __construct(LoanService $loanService)
    {
        $this->loanService = $loanService;
    }

    /**
     * Display loan products available to member.
     */
    public function products()
    {
        $member = $this->getMember();

        if (!$member) {
            return redirect()->route('login')
                ->withErrors(['error' => 'Member profile not found. Please contact support.']);
        }

        if (!$member->isActive()) {
            return redirect()->route('member.dashboard')
                ->withErrors(['error' => 'Your membership is not active. Please contact support.']);
        }

        $products = LoanProduct::active()
            ->ordered()
            ->get()
            ->filter(function ($product) use ($member) {
                return $member->canApplyForLoan($product);
            });

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

    /**
     * Display loan application form.
     */
    public function create(LoanProduct $loanProduct)
    {
        $member = $this->getMember();

        if (!$member) {
            return redirect()->route('login');
        }

        if (!$member->isActive()) {
            return redirect()->route('member.dashboard')
                ->withErrors(['error' => 'Your membership is not active.']);
        }

        if (!$loanProduct->is_active) {
            abort(404, 'This loan product is not available.');
        }

        if (!$member->canApplyForLoan($loanProduct)) {
            return redirect()->route('member.loans.products')
                ->withErrors(['error' => 'You are not eligible for this loan product.']);
        }

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

    /**
     * Submit loan application.
     */
    public function store(Request $request, LoanProduct $loanProduct)
    {
        $member = $this->getMember();

        if (!$member) {
            return redirect()->route('login');
        }

        if (!$member->isActive()) {
            return redirect()->route('member.dashboard')
                ->withErrors(['error' => 'Your membership is not active.']);
        }

        if (!$loanProduct->is_active) {
            abort(404, 'This loan product is not available.');
        }

        if (!$member->canApplyForLoan($loanProduct)) {
            return redirect()->route('member.loans.products')
                ->withErrors(['error' => 'You are not eligible for this loan product.']);
        }

        $request->validate([
            'amount_requested' => 'required|numeric|min:' . $loanProduct->min_amount . '|max:' . $loanProduct->max_amount,
            'term_months' => 'required|integer|min:' . $loanProduct->min_term_months . '|max:' . $loanProduct->max_term_months,
            'purpose' => 'required|string|max:1000',
            'employment_status' => 'nullable|string|in:employed,self_employed,business_owner,retired,other',
            'employer_name' => 'nullable|string|max:191',
            'monthly_income' => 'nullable|numeric|min:0',
            'income_currency' => 'nullable|in:USD,SSP,KES,UGX',
            'documents' => 'nullable|array',
            'documents.*' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:5120',
        ], [
            'amount_requested.required' => 'Loan amount is required.',
            'amount_requested.min' => 'Minimum loan amount is ' . number_format($loanProduct->min_amount, 2) . ' ' . $loanProduct->currency,
            'amount_requested.max' => 'Maximum loan amount is ' . number_format($loanProduct->max_amount, 2) . ' ' . $loanProduct->currency,
            'term_months.required' => 'Loan term is required.',
            'term_months.min' => 'Minimum term is ' . $loanProduct->min_term_months . ' months.',
            'term_months.max' => 'Maximum term is ' . $loanProduct->max_term_months . ' months.',
            'purpose.required' => 'Please describe the purpose of the loan.',
            'documents.*.mimes' => 'Documents must be PDF, JPG, or PNG files.',
            'documents.*.max' => 'Each document must be under 5MB.',
        ]);

        $application = $this->loanService->submitApplication($member, $loanProduct, [
            'amount_requested' => (float) $request->amount_requested,
            'term_months' => (int) $request->term_months,
            'purpose' => strip_tags($request->purpose),
            'employment_status' => $request->employment_status ?: null,
            'employer_name' => $request->employer_name ? strip_tags($request->employer_name) : null,
            'monthly_income' => $request->monthly_income ? (float) $request->monthly_income : null,
            'income_currency' => $request->income_currency ?: null,
        ]);

        // Handle document uploads (keyed by document type: documents[id_document], etc.)
        if ($request->hasFile('documents')) {
            foreach ($request->file('documents') as $documentType => $file) {
                if ($file && $file->isValid()) {
                    $this->loanService->uploadDocument(
                        $application,
                        $file,
                        (string) $documentType,
                        auth()->id()
                    );
                }
            }
        }

        return redirect()->route('member.loans.show', $application)
            ->with('success', 'Your loan application has been submitted successfully. You will be notified once it is reviewed.');
    }

    /**
     * Display member's loan applications.
     */
    public function index()
    {
        $member = $this->getMember();

        if (!$member) {
            return redirect()->route('login');
        }

        $applications = $member->loanApplications()
            ->with('loanProduct')
            ->latest()
            ->paginate(10);

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

    /**
     * Display loan application details.
     */
    public function show(LoanApplication $loanApplication)
    {
        $member = $this->getMember();

        if (!$member || $loanApplication->member_id !== $member->id) {
            abort(403, 'Unauthorized access to this loan application.');
        }

        $loanApplication->load(['loanProduct', 'documents', 'repayments']);

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

    /**
     * Display loan repayment schedule.
     */
    public function repaymentSchedule(LoanApplication $loanApplication)
    {
        $member = $this->getMember();

        if (!$member || $loanApplication->member_id !== $member->id) {
            abort(403, 'Unauthorized access.');
        }

        $loanApplication->load(['loanProduct', 'repayments', 'amortizationSchedule']);

        return view('loans.member.repayment-schedule', compact('member', 'loanApplication'));
    }

    /**
     * Make loan repayment.
     */
    public function makeRepayment(LoanApplication $loanApplication)
    {
        $member = $this->getMember();

        if (!$member || $loanApplication->member_id !== $member->id) {
            abort(403, 'Unauthorized access.');
        }

        if (!in_array($loanApplication->status, ['active', 'disbursed'])) {
            return redirect()->route('member.loans.show', $loanApplication)
                ->withErrors(['error' => 'This loan is not active.']);
        }

        // Get next pending repayment
        $nextRepayment = $loanApplication->repayments()
            ->whereIn('status', ['scheduled', 'pending', 'overdue'])
            ->orderBy('installment_number')
            ->first();

        if (!$nextRepayment) {
            return redirect()->route('member.loans.show', $loanApplication)
                ->withErrors(['error' => 'No pending repayments found.']);
        }

        // Collect all overdue installments so the member can see what's outstanding
        $overdueRepayments = $loanApplication->repayments()
            ->where(function ($q) {
                $q->where('status', 'overdue')
                    ->orWhere(function ($q2) {
                        $q2->whereIn('status', ['scheduled', 'pending'])
                            ->where('due_date', '<', now());
                    });
            })
            ->orderBy('installment_number')
            ->get();

        return view('loans.member.make-repayment', compact('member', 'loanApplication', 'nextRepayment', 'overdueRepayments'));
    }

    /**
     * Process loan repayment.
     */
    public function processRepayment(Request $request, LoanApplication $loanApplication)
    {
        $member = $this->getMember();

        if (!$member || $loanApplication->member_id !== $member->id) {
            abort(403, 'Unauthorized access.');
        }

        $paymentMethod = $request->input('payment_method', 'mobile');

        $rules = [
            'repayment_id'   => 'required|exists:loan_repayments,id',
            'payment_method' => 'nullable|in:mobile,card',
        ];

        if ($paymentMethod === 'card') {
            $rules['card_number'] = 'required|string';
            $rules['card_expiry'] = ['required', 'regex:/^(0[1-9]|1[0-2])\/\d{2}$/'];
            $rules['card_cvv']    = 'required|digits_between:3,4';
        } else {
            $rules['phone_number'] = 'required|string|regex:/^[0-9+]{9,15}$/';
        }

        $request->validate($rules, [
            'phone_number.required' => 'Phone number is required for MTN MoMo payment.',
            'phone_number.regex'    => 'Please enter a valid phone number.',
            'card_number.required'  => 'Card number is required.',
            'card_expiry.required'  => 'Card expiry date is required.',
            'card_cvv.required'     => 'CVV is required.',
        ]);

        $repayment = \App\Models\LoanRepayment::findOrFail($request->repayment_id);

        if ($repayment->loan_application_id !== $loanApplication->id) {
            abort(403, 'Invalid repayment.');
        }

        // Normalise phone: strip non-digits and leading zeros for MSISDN format
        $phone = '';
        if ($paymentMethod !== 'card') {
            $phone = preg_replace('/\D/', '', $request->phone_number);
            $phone = ltrim($phone, '0');
        }

        $result = $this->loanService->processRepayment(
            repayment: $repayment,
            phoneNumber: $phone,
            paymentMethod: $paymentMethod,
            cardNumber: $request->input('card_number'),
            cardExpiry: $request->input('card_expiry'),
            cardCvv: $request->input('card_cvv'),
        );

        if ($result['success']) {
            return redirect()->route('member.loans.payment-status', [
                    $loanApplication,
                    \App\Models\MembershipTransaction::where('transaction_reference', $result['transaction_reference'])->firstOrFail(),
                ])
                ->with('success', $result['message']);
        }

        return redirect()->back()
            ->withErrors(['error' => $result['message']]);
    }

    /**
     * Show payment status page (polling-friendly).
     */
    public function paymentStatus(LoanApplication $loanApplication, \App\Models\MembershipTransaction $transaction)
    {
        $member = $this->getMember();

        if (!$member || $loanApplication->member_id !== $member->id) {
            abort(403, 'Unauthorized access.');
        }

        if ($transaction->loan_application_id !== $loanApplication->id) {
            abort(403, 'Invalid transaction.');
        }

        $loanApplication->load(['loanProduct', 'repayments']);

        return view('loans.member.payment-status', compact('member', 'loanApplication', 'transaction'));
    }

    /**
     * AJAX endpoint: return current transaction status for polling.
     */
    public function paymentStatusCheck(LoanApplication $loanApplication, \App\Models\MembershipTransaction $transaction)
    {
        $member = $this->getMember();

        if (!$member || $loanApplication->member_id !== $member->id) {
            abort(403);
        }

        if ($transaction->loan_application_id !== $loanApplication->id) {
            abort(403);
        }

        // Refresh from DB to get latest status
        $transaction->refresh();
        $loanApplication->refresh();

        return response()->json([
            'status'              => $transaction->status,
            'error_message'       => $transaction->error_message,
            'amount_paid'         => $transaction->amount,
            'outstanding_balance' => $loanApplication->outstanding_balance,
            'external_reference'  => $transaction->external_reference,
        ]);
    }

    /**
     * Get the authenticated member.
     */
    protected function getMember(): ?Member
    {
        return Member::where('user_id', auth()->id())->first();
    }
}
