<?php

namespace App\Http\Controllers;

use App\Models\Cause;
use App\Models\Donation;
use App\Models\Donor;
use App\Models\FundCollection;
use App\Models\Project;
use App\Services\SslCommerzService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class DonationController extends Controller
{
    /**
     * Initiate a donation checkout process and return a real SSLCommerz sandbox redirect.
     */
    public function initiate(Request $request): JsonResponse
    {
        $source = $request->input('source', 'checkout');
        $isQuick = $source === 'quick';

        $validator = Validator::make($request->all(), [
            'amount'               => 'required|numeric|min:10',
            'cause_id'             => 'required_without_all:fund_collection_id,project_id|nullable|exists:causes,id',
            'fund_collection_id'   => 'required_without_all:cause_id,project_id|nullable|exists:fund_collections,id',
            'project_id'           => 'required_without_all:cause_id,fund_collection_id|nullable|exists:projects,id',
            'name'         => $isQuick ? 'nullable|string|max:255' : 'required|string|max:255',
            'email'        => $isQuick ? 'nullable|email|max:255' : 'required|email|max:255',
            'phone'        => $isQuick ? 'required|string|max:20' : 'nullable|string|max:20',
            'is_anonymous' => 'nullable|boolean',
            'source'       => 'nullable|in:checkout,quick',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 'error',
                'errors' => $validator->errors()
            ], 422);
        }

        // 1. Find or create the Donor record
        //    For quick donations, email may be absent — use phone as unique key fallback
        $donorEmail = $request->email ?: ('phone+' . $request->phone . '@quick.horizonwelfare.org');
        $donor = Donor::firstOrCreate(
            ['email' => $donorEmail],
            [
                'name'  => $request->name ?: 'Quick Donor',
                'phone' => $request->phone
            ]
        );

        // Update phone if it was null previously but provided now
        if ($request->phone && !$donor->phone) {
            $donor->update(['phone' => $request->phone]);
        }

        // 2. Generate unique Transaction ID
        $transactionId = 'HW-' . time() . '-' . rand(1000, 9999);

        // 3. Create Pending Donation
        $donation = Donation::create([
            'donor_id'           => $donor->id,
            'cause_id'           => $request->cause_id,
            'fund_collection_id' => $request->fund_collection_id,
            'project_id'         => $request->project_id,
            'amount'             => $request->amount,
            'currency'        => 'BDT',
            'transaction_id'  => $transactionId,
            'payment_gateway' => 'sslcommerz',
            'status'          => 'pending',
            'is_anonymous'    => (bool) $request->is_anonymous,
            'source'          => $source,
        ]);

        // 4. Request SSLCommerz checkout session URL
        $sslService = new SslCommerzService();
        $gatewayUrl = $sslService->initiatePayment($donation);

        if (!$gatewayUrl) {
            return response()->json([
                'status' => 'error',
                'message' => 'Failed to connect to SSLCommerz gateway. Please try again.'
            ], 500);
        }

        return response()->json([
            'status' => 'success',
            'transaction_id' => $transactionId,
            'redirect_url' => $gatewayUrl
        ]);
    }

    /**
     * Handle successful payment redirect from SSLCommerz.
     */
    public function success(Request $request)
    {
        $tranId = $request->input('tran_id');
        $valId = $request->input('val_id');

        $donation = Donation::where('transaction_id', $tranId)->firstOrFail();
        $redirectUrl = config('services.sslcommerz.frontend_redirect');

        // Check if transaction has already been completed
        if ($donation->status === 'completed') {
            return redirect($redirectUrl . '/?payment=success&trx_id=' . $tranId . '&amount=' . $donation->amount);
        }

        // Validate the transaction with SSLCommerz servers
        $sslService = new SslCommerzService();
        $isValid = $sslService->validatePayment($valId);

        if ($isValid) {
            $donation->update(['status' => 'completed']);
            
            if ($donation->cause_id) {
                $cause = Cause::find($donation->cause_id);
                if ($cause) {
                    $cause->increment('raised_amount', $donation->amount);
                }
            } elseif ($donation->fund_collection_id) {
                $fund = FundCollection::find($donation->fund_collection_id);
                if ($fund) {
                    $fund->increment('raised_amount', $donation->amount);
                }
            } elseif ($donation->project_id) {
                $project = Project::find($donation->project_id);
                if ($project) {
                    $project->increment('total_fund_raised', $donation->amount);
                }
            }

            return redirect($redirectUrl . '/?payment=success&trx_id=' . $tranId . '&amount=' . $donation->amount);
        } else {
            $donation->update(['status' => 'failed']);
            return redirect($redirectUrl . '/?payment=failed&trx_id=' . $tranId);
        }
    }

    /**
     * Handle failed payment redirect from SSLCommerz.
     */
    public function fail(Request $request)
    {
        $tranId = $request->input('tran_id');
        
        $donation = Donation::where('transaction_id', $tranId)->first();
        if ($donation && $donation->status === 'pending') {
            $donation->update(['status' => 'failed']);
        }

        $redirectUrl = config('services.sslcommerz.frontend_redirect');
        return redirect($redirectUrl . '/?payment=failed&trx_id=' . $tranId);
    }

    /**
     * Handle canceled payment redirect from SSLCommerz.
     */
    public function cancel(Request $request)
    {
        $tranId = $request->input('tran_id');

        $donation = Donation::where('transaction_id', $tranId)->first();
        if ($donation && $donation->status === 'pending') {
            $donation->update(['status' => 'failed']);
        }

        $redirectUrl = config('services.sslcommerz.frontend_redirect');
        return redirect($redirectUrl . '/?payment=cancelled&trx_id=' . $tranId);
    }

    /**
     * Handle asynchronous Instant Payment Notification (IPN) from SSLCommerz.
     */
    public function ipn(Request $request): JsonResponse
    {
        $tranId = $request->input('tran_id');
        $valId = $request->input('val_id');

        $donation = Donation::where('transaction_id', $tranId)->first();

        if ($donation && $donation->status === 'pending') {
            $sslService = new SslCommerzService();
            $isValid = $sslService->validatePayment($valId);

            if ($isValid) {
                $donation->update(['status' => 'completed']);
                
                if ($donation->cause_id) {
                    $cause = Cause::find($donation->cause_id);
                    if ($cause) {
                        $cause->increment('raised_amount', $donation->amount);
                    }
                } elseif ($donation->fund_collection_id) {
                    $fund = FundCollection::find($donation->fund_collection_id);
                    if ($fund) {
                        $fund->increment('raised_amount', $donation->amount);
                    }
                } elseif ($donation->project_id) {
                    $project = Project::find($donation->project_id);
                    if ($project) {
                        $project->increment('total_fund_raised', $donation->amount);
                    }
                }
                return response()->json(['status' => 'success', 'message' => 'IPN callback processed successfully.']);
            } else {
                $donation->update(['status' => 'failed']);
                return response()->json(['status' => 'error', 'message' => 'Invalid payment callback credentials.'], 400);
            }
        }

        return response()->json(['status' => 'success', 'message' => 'Transaction already finalized.']);
    }

    /**
     * Handle manual local mock webhook callback.
     */
    public function webhook(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'transaction_id' => 'required|exists:donations,transaction_id',
            'status' => 'required|in:completed,failed',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status' => 'error',
                'errors' => $validator->errors()
            ], 422);
        }

        $donation = Donation::where('transaction_id', $request->transaction_id)->firstOrFail();

        if (in_array($donation->status, ['completed', 'failed'])) {
            return response()->json([
                'status' => 'success',
                'message' => 'Donation already finalized as ' . $donation->status
            ]);
        }

        $donation->update(['status' => $request->status]);

        if ($request->status === 'completed') {
            if ($donation->cause_id) {
                $cause = Cause::find($donation->cause_id);
                if ($cause) {
                    $cause->increment('raised_amount', $donation->amount);
                }
            } elseif ($donation->fund_collection_id) {
                $fund = FundCollection::find($donation->fund_collection_id);
                if ($fund) {
                    $fund->increment('raised_amount', $donation->amount);
                }
            }
        }

        return response()->json([
            'status' => 'success',
            'message' => 'Donation status updated to ' . $request->status
        ]);
    }
}
