<?php

namespace App\Http\Controllers;

use App\Services\MpesaService;
use App\Models\MpesaTransaction;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
use App\Notifications\OrderPaidNotification;
use App\Models\User;
use Illuminate\Support\Facades\Cache;

class PaymentController extends Controller
{
    protected $mpesaService;
    
    public function __construct(MpesaService $mpesaService)
    {
        $this->mpesaService = $mpesaService;
    }
    
    /**
     * Show Payment Page
     */
    public function showPayment()
    {
        // Get cart from session or database
        $cart = Session::get('cart', []);
        $subtotal = Session::get('cart_subtotal', 0);
        $total = Session::get('cart_total', 0);
        
        if (empty($cart)) {
            return redirect()->route('cart.view')->with('error', 'Your cart is empty');
        }
        
        return view('checkout', [
            'cart' => $cart,
            'subtotal' => $subtotal,
            'total' => $total,
            'tax' => 0, // No tax for now
            'shipping' => 0, // No shipping for now
        ]);
    }
    
    /**
     * Process M-Pesa Payment (AJAX)
     */
    public function processMpesaPayment(Request $request)
    {
        // Validate request - use more flexible validation
        $validator = Validator::make($request->all(), [
            'phone' => 'required',
            'amount' => 'required|numeric|min:1|max:150000',
        ]);
        
        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => $validator->errors()->first()
            ], 422);
        }
        
        // Get cart total from session or use provided amount
        $amount = $request->amount;
        $phone = $request->phone;
        
        // Clean the phone number - remove all non-digits first
        $cleanPhone = preg_replace('/[^0-9]/', '', $phone);
        
        // Basic validation for Kenyan mobile numbers
        if (strlen($cleanPhone) < 9 || strlen($cleanPhone) > 12) {
            return response()->json([
                'success' => false,
                'message' => 'Please enter a valid Kenyan phone number (9-12 digits)'
            ], 422);
        }
        
        // Generate a unique reference
        $reference = 'FP_' . time() . '_' . (Auth::id() ?? 'guest');
        
        // Description for payment
        $description = 'Payment for electronics purchase - Finepoint';
        
        Log::info('Initiating M-Pesa payment:', [
            'phone' => $phone,
            'clean_phone' => $cleanPhone,
            'amount' => $amount,
            'reference' => $reference,
            'user_id' => Auth::id() ?? 'guest'
        ]);
        
        // Create transaction record in database
        $mpesaTransaction = MpesaTransaction::create([
            'phone_number' => $cleanPhone,
            'amount' => $amount,
            'account_reference' => $reference,
            'transaction_desc' => $description,
            'status' => 'pending',
            'user_id' => Auth::id(),
            'request_data' => $request->all()
        ]);
        
        // Initiate STK Push - use the cleaned phone
        $result = $this->mpesaService->stkPush($cleanPhone, $amount, $reference, $description);
        
        if ($result['success']) {
            // Update transaction with checkout request IDs
            $mpesaTransaction->update([
                'checkout_request_id' => $result['checkout_request_id'],
                'merchant_request_id' => $result['merchant_request_id'],
                'response_data' => $result
            ]);
            
            // Store payment details in session
            $paymentData = [
                'transaction_id' => $mpesaTransaction->id,
                'checkout_request_id' => $result['checkout_request_id'],
                'merchant_request_id' => $result['merchant_request_id'],
                'phone' => $cleanPhone,
                'amount' => $amount,
                'reference' => $reference,
                'timestamp' => now(),
                'status' => 'pending'
            ];
            
            Session::put('mpesa_payment_' . $result['checkout_request_id'], $paymentData);
            Session::put('current_checkout_id', $result['checkout_request_id']);
            Session::put('current_transaction_id', $mpesaTransaction->id);
            
            return response()->json([
                'success' => true,
                'message' => $result['customer_message'],
                'checkout_request_id' => $result['checkout_request_id'],
                'customer_message' => $result['customer_message'],
                'transaction_id' => $mpesaTransaction->id
            ]);
        } else {
            // Update transaction as failed
            $mpesaTransaction->update([
                'status' => 'failed',
                'response_code' => 'STK_FAILED',
                'response_description' => $result['message'],
                'response_data' => $result
            ]);
            
            return response()->json([
                'success' => false,
                'message' => $result['message']
            ], 400);
        }
    }
    
    /**
     * Check Payment Status (AJAX) - FIXED with caching and rate limiting
     */
    public function checkPaymentStatus(Request $request)
    {
        Log::info('=== M-PESA STATUS CHECK STARTED ===');
        
        $checkoutRequestId = $request->query('checkout_request_id');
        
        if (!$checkoutRequestId) {
            Log::error('No checkout request ID provided');
            return response()->json([
                'success' => false,
                'message' => 'No checkout request ID provided'
            ]);
        }
        
        // Check cache first to avoid too many API calls
        $cacheKey = 'mpesa_status_' . $checkoutRequestId;
        $cachedResult = Cache::get($cacheKey);
        
        if ($cachedResult) {
            Log::info('Returning cached status for: ' . $checkoutRequestId);
            return response()->json($cachedResult);
        }
        
        // Find transaction
        $transaction = MpesaTransaction::where('checkout_request_id', $checkoutRequestId)->first();
        
        if (!$transaction) {
            Log::error('Transaction not found for checkout request: ' . $checkoutRequestId);
            return response()->json([
                'success' => false,
                'message' => 'Transaction not found',
                'status' => 'unknown'
            ]);
        }
        
        Log::info('Transaction found, current status: ' . $transaction->status . ', ID: ' . $transaction->id);
        
        // If transaction is already marked as success, return immediately
        if ($transaction->status === 'success') {
            Log::info('Transaction already successful, returning result');
            
            $result = [
                'success' => true,
                'status' => 'completed',
                'message' => 'Payment completed successfully',
                'transaction_id' => $transaction->id
            ];
            
            // Cache for 5 minutes
            Cache::put($cacheKey, $result, 300);
            
            return response()->json($result);
        }
        
        // If transaction failed, return failure
        if ($transaction->status === 'failed') {
            $result = [
                'success' => false,
                'status' => 'failed',
                'message' => $transaction->response_description ?? 'Payment failed'
            ];
            
            // Cache for 2 minutes
            Cache::put($cacheKey, $result, 120);
            
            return response()->json($result);
        }
        
        // Check if we should query M-Pesa API (limit calls to prevent rate limiting)
        $lastChecked = $transaction->last_checked_at ?? $transaction->created_at;
        $secondsSinceLastCheck = now()->diffInSeconds($lastChecked);
        $transactionAge = now()->diffInSeconds($transaction->created_at);
        
        Log::info('Time since last check: ' . $secondsSinceLastCheck . 's, Transaction age: ' . $transactionAge . 's');
        
        // Only query M-Pesa API if:
        // 1. Transaction is still pending, AND
        // 2. At least 15 seconds have passed since last check, AND
        // 3. Transaction is less than 5 minutes old (M-Pesa STK push expires after 5 minutes)
        $shouldQueryMpesa = $transaction->status === 'pending' && 
                           $secondsSinceLastCheck >= 15 && 
                           $transactionAge < 300;
        
        if ($shouldQueryMpesa) {
            Log::info('Querying M-Pesa API for status...');
            
            // Update last checked time
            $transaction->update(['last_checked_at' => now()]);
            
            try {
                // Check status from M-Pesa
                $status = $this->mpesaService->checkStkStatus($checkoutRequestId);
                
                if (!$status) {
                    Log::warning('Failed to get status from M-Pesa API');
                    
                    $pendingResult = [
                        'success' => true,
                        'status' => 'pending',
                        'message' => 'Payment still processing...'
                    ];
                    
                    // Cache for 10 seconds to prevent too many calls
                    Cache::put($cacheKey, $pendingResult, 10);
                    
                    return response()->json($pendingResult);
                }
                
                Log::info('Payment status check result:', (array)$status);
                
                // Parse the response
                if (isset($status->ResultCode)) {
                    $resultCode = (string) $status->ResultCode;
                    
                    if ($resultCode === '0') {
                        // Payment successful
                        $transaction->markAsSuccess([
                            'ResultCode' => $resultCode,
                            'ResultDesc' => $status->ResultDesc ?? 'Success',
                            'response_data' => (array)$status
                        ]);
                        
                        $successResult = [
                            'success' => true,
                            'status' => 'completed',
                            'message' => 'Payment completed successfully',
                            'transaction_id' => $transaction->id
                        ];
                        
                        // Cache for 5 minutes
                        Cache::put($cacheKey, $successResult, 300);
                        
                        return response()->json($successResult);
                        
                    } else {
                        // Payment failed or cancelled
                        $errorMessages = [
                            '1' => 'The balance is insufficient for the transaction',
                            '1032' => 'Request cancelled by user',
                            '1037' => 'Timeout - No response from user',
                            '2001' => 'Invalid phone number format'
                        ];
                        
                        $errorMessage = $errorMessages[$resultCode] ?? $status->ResultDesc ?? 'Payment failed';
                        
                        $transaction->markAsFailed([
                            'ResultCode' => $resultCode,
                            'ResultDesc' => $errorMessage,
                            'response_data' => (array)$status
                        ]);
                        
                        $failedResult = [
                            'success' => false,
                            'message' => $errorMessage,
                            'status' => 'failed',
                            'result_code' => $resultCode,
                            'transaction_id' => $transaction->id
                        ];
                        
                        // Cache for 2 minutes
                        Cache::put($cacheKey, $failedResult, 120);
                        
                        return response()->json($failedResult);
                    }
                }
                
            } catch (\Exception $e) {
                Log::error('M-Pesa status check exception: ' . $e->getMessage());
                
                // If we get rate limited or other errors, return pending
                $errorResult = [
                    'success' => true,
                    'status' => 'pending',
                    'message' => 'Checking payment status...'
                ];
                
                // Cache for 30 seconds on error
                Cache::put($cacheKey, $errorResult, 30);
                
                return response()->json($errorResult);
            }
        }
        
        // Default response - still pending
        Log::info('Payment still pending for: ' . $checkoutRequestId);
        
        $pendingResponse = [
            'success' => true,
            'status' => 'pending',
            'message' => 'Payment still processing...'
        ];
        
        // Cache for 10 seconds to prevent too many calls
        Cache::put($cacheKey, $pendingResponse, 10);
        
        return response()->json($pendingResponse);
    }
    
    /**
     * M-Pesa Callback URL (Webhook) - This is called by Safaricom
     */
    public function mpesaCallback(Request $request)
    {
        // Log the full callback for debugging
        $callbackData = $request->all();
        Log::info('M-Pesa Callback Received:', $callbackData);
        
        // Validate callback structure
        if (!isset($callbackData['Body']['stkCallback'])) {
            Log::error('Invalid M-Pesa callback structure');
            return response()->json([
                'ResultCode' => 1,
                'ResultDesc' => 'Invalid callback'
            ]);
        }
        
        $stkCallback = $callbackData['Body']['stkCallback'];
        $checkoutRequestId = $stkCallback['CheckoutRequestID'] ?? null;
        $resultCode = $stkCallback['ResultCode'] ?? null;
        $resultDesc = $stkCallback['ResultDesc'] ?? '';
        
        if (!$checkoutRequestId || !$resultCode) {
            Log::error('Missing required callback data');
            return response()->json([
                'ResultCode' => 1,
                'ResultDesc' => 'Missing data'
            ]);
        }
        
        Log::info('Processing callback:', [
            'checkout_request_id' => $checkoutRequestId,
            'result_code' => $resultCode,
            'result_desc' => $resultDesc
        ]);
        
        // Find transaction in database
        $transaction = MpesaTransaction::where('checkout_request_id', $checkoutRequestId)->first();
        
        if (!$transaction) {
            Log::error('Transaction not found for callback:', ['checkout_request_id' => $checkoutRequestId]);
            return response()->json([
                'ResultCode' => 1,
                'ResultDesc' => 'Transaction not found'
            ]);
        }
        
        // Clear cache for this transaction
        Cache::forget('mpesa_status_' . $checkoutRequestId);
        
        // Handle based on result code
        if ($resultCode == 0) {
            // Payment successful
            $callbackMetadata = $stkCallback['CallbackMetadata']['Item'] ?? [];
            
            // Extract important data from metadata
            $mpesaReceiptNumber = '';
            $phoneNumber = '';
            $amount = 0;
            $transactionDate = '';
            
            foreach ($callbackMetadata as $item) {
                if ($item['Name'] == 'MpesaReceiptNumber') {
                    $mpesaReceiptNumber = $item['Value'];
                } elseif ($item['Name'] == 'PhoneNumber') {
                    $phoneNumber = $item['Value'];
                } elseif ($item['Name'] == 'Amount') {
                    $amount = $item['Value'];
                } elseif ($item['Name'] == 'TransactionDate') {
                    $transactionDate = $item['Value'];
                }
            }
            
            // Update transaction as successful
            $transaction->markAsSuccess([
                'ResultCode' => $resultCode,
                'ResultDesc' => $resultDesc,
                'TransactionID' => $mpesaReceiptNumber,
                'TransactionDate' => $transactionDate,
                'PhoneNumber' => $phoneNumber,
                'Amount' => $amount,
                'response_data' => $callbackData
            ]);
            
            // Store in session for immediate access
            Session::put('mpesa_callback_' . $checkoutRequestId, [
                'transaction_id' => $transaction->id,
                'mpesa_receipt' => $mpesaReceiptNumber,
                'phone' => $phoneNumber,
                'amount' => $amount,
                'transaction_date' => $transactionDate,
                'received_at' => now()->toDateTimeString()
            ]);
            
            Log::info('Payment Successfully Processed in Callback:', [
                'transaction_id' => $transaction->id,
                'mpesa_receipt' => $mpesaReceiptNumber,
                'status' => 'success'
            ]);
            
        } else {
            // Payment failed
            $transaction->markAsFailed([
                'ResultCode' => $resultCode,
                'ResultDesc' => $resultDesc,
                'response_data' => $callbackData
            ]);
            
            Log::error('Payment Failed in Callback:', [
                'transaction_id' => $transaction->id,
                'checkout_request_id' => $checkoutRequestId,
                'result_code' => $resultCode,
                'result_desc' => $resultDesc
            ]);
            
            // Store failure in session
            Session::put('mpesa_failure_' . $checkoutRequestId, [
                'transaction_id' => $transaction->id,
                'checkout_request_id' => $checkoutRequestId,
                'result_code' => $resultCode,
                'result_desc' => $resultDesc,
                'failed_at' => now()->toDateTimeString()
            ]);
        }
        
        // Always return success to M-Pesa
        return response()->json([
            'ResultCode' => 0,
            'ResultDesc' => 'Callback processed successfully'
        ]);
    }
    
    /**
     * Process Checkout (Final Step) - FIXED VERSION
     */
    public function processCheckout(Request $request)
    {
        // Validate the request
        $validated = $request->validate([
            'shipping_name' => 'required|string|max:255',
            'shipping_email' => 'required|email|max:255',
            'shipping_phone' => 'required|string|max:20',
            'shipping_address' => 'required|string|max:500',
            'shipping_city' => 'required|string|max:100',
            'shipping_state' => 'required|string|max:100',
            'shipping_zip' => 'required|string|max:20',
            'shipping_country' => 'required|string|max:100',
            'payment_method' => 'required|in:cod,mpesa',
            'shipping_notes' => 'nullable|string',
            'billing_same' => 'nullable',
            'billing_name' => 'nullable|string|max:255',
            'billing_address' => 'nullable|string|max:500',
            'checkout_request_id' => 'nullable|string',
        ]);
        
        // Get cart items from database (for logged-in users) or session
        $cartItems = [];
        $subtotal = 0;
        
        if (Auth::check()) {
            // Get from database for logged-in users
            $cartItems = \App\Models\Cart::with('product')
                ->where('user_id', Auth::id())
                ->get();
        } else {
            // Get from session for guests
            $sessionCart = Session::get('cart', []);
            foreach ($sessionCart as $item) {
                $product = Product::find($item['product_id']);
                if ($product) {
                    $cartItems[] = (object)[
                        'product' => $product,
                        'quantity' => $item['quantity']
                    ];
                }
            }
            $cartItems = collect($cartItems);
        }
        
        // Check if cart is empty
        if ($cartItems->count() == 0) {
            return redirect()->route('cart.view')
                ->with('error', 'Your cart is empty')
                ->withInput();
        }
        
        // Calculate totals from actual cart items
        $subtotal = 0;
        foreach ($cartItems as $item) {
            $subtotal += $item->product->price * $item->quantity;
        }
        
        // No tax or shipping for now
        $tax = 0;
        $shipping = 0;
        $total = $subtotal;
        
        // Prepare shipping address as array for JSON storage
        $shippingAddress = [
            'name' => $validated['shipping_name'],
            'email' => $validated['shipping_email'],
            'phone' => $validated['shipping_phone'],
            'address' => $validated['shipping_address'],
            'city' => $validated['shipping_city'],
            'state' => $validated['shipping_state'],
            'zip' => $validated['shipping_zip'],
            'country' => $validated['shipping_country'],
            'notes' => $validated['shipping_notes'] ?? null
        ];
        
        // Prepare billing address
        if (isset($validated['billing_same']) && $validated['billing_same']) {
            $billingAddress = $shippingAddress;
        } else {
            $billingAddress = [
                'name' => $validated['billing_name'] ?? $validated['shipping_name'],
                'address' => $validated['billing_address'] ?? $validated['shipping_address'],
                'city' => $validated['shipping_city'],
                'state' => $validated['shipping_state'],
                'zip' => $validated['shipping_zip'],
                'country' => $validated['shipping_country']
            ];
        }
        
        // Check M-Pesa payment verification if paying with M-Pesa
        $paymentVerified = false;
        $mpesaTransaction = null;
        
        if ($validated['payment_method'] === 'mpesa') {
            // Get current transaction ID from session
            $transactionId = Session::get('current_transaction_id');
            $checkoutRequestId = $validated['checkout_request_id'] ?? Session::get('current_checkout_id');
            
            if ($transactionId) {
                $mpesaTransaction = MpesaTransaction::find($transactionId);
                
                if ($mpesaTransaction && $mpesaTransaction->status === 'success') {
                    $paymentVerified = true;
                    
                    // Verify amount matches
                    if (abs($mpesaTransaction->amount - $total) > 1) { // Allow 1 Ksh difference
                        return redirect()->back()
                            ->with('error', 'Payment amount does not match order total. Paid: Ksh ' . 
                                   number_format($mpesaTransaction->amount, 2) . 
                                   ', Order Total: Ksh ' . number_format($total, 2))
                            ->withInput();
                    }
                }
            }
            
            if (!$paymentVerified) {
                return redirect()->back()
                    ->with('error', 'M-Pesa payment not verified. Please complete payment first.')
                    ->withInput();
            }
        }
        
        try {
            // Create the order
            $order = Order::create([
                'order_number' => Order::generateOrderNumber(),
                'user_id' => Auth::id(),
                'subtotal' => $subtotal,
                'tax' => $tax,
                'shipping' => $shipping,
                'total' => $total,
                'status' => 'pending',
                'payment_status' => $validated['payment_method'] === 'mpesa' ? 'paid' : 'pending',
                'payment_method' => $validated['payment_method'],
                'shipping_address' => json_encode($shippingAddress),
                'billing_address' => json_encode($billingAddress),
                'customer_name' => $validated['shipping_name'],
                'customer_email' => $validated['shipping_email'],
                'customer_phone' => $validated['shipping_phone'],
                'notes' => $validated['shipping_notes'] ?? null
            ]);
            
            // Create order items
            foreach ($cartItems as $item) {
                OrderItem::create([
                    'order_id' => $order->id,
                    'product_id' => $item->product->id,
                    'product_name' => $item->product->name,
                    'price' => $item->product->price,
                    'quantity' => $item->quantity,
                    'total' => $item->product->price * $item->quantity,
                ]);
                
                // Update product stock
                $item->product->decrement('stock', $item->quantity);
            }
            
            // Link M-Pesa transaction to order if applicable
            if ($mpesaTransaction) {
                $mpesaTransaction->update([
                    'order_id' => $order->id,
                    'status' => 'success'
                ]);
            }

            if (Auth::check() && $order->user) {
        $order->user->notify(new OrderPaidNotification($order));
    }

     $admin = User::where('role', 'admin')->first();
    if ($admin) {
        $admin->notify(new OrderPaidNotification($order));
    }
            
            // Clear cart
            if (Auth::check()) {
                \App\Models\Cart::where('user_id', Auth::id())->delete();
            } else {
                Session::forget('cart');
            }
            
            // Clear session data
            Session::forget('cart_subtotal');
            Session::forget('cart_total');
            Session::forget('current_checkout_id');
            Session::forget('current_transaction_id');
            
            // Redirect to order confirmation page
            return redirect()->route('order.confirmation', ['order_id' => $order->id])
                ->with('success', 'Order placed successfully!')
                ->with('order_number', $order->order_number);
                
        } catch (\Exception $e) {
            Log::error('Checkout Error: ' . $e->getMessage());
            Log::error($e->getTraceAsString());
            
            return redirect()->back()
                ->with('error', 'Failed to place order. Please try again. Error: ' . $e->getMessage())
                ->withInput();
        }
    }
    
    /**
     * Order Confirmation Page
     */
    public function orderConfirmation($order_id)
    {
        $order = Order::with(['items.product', 'mpesaTransactions'])
            ->find($order_id);
        
        if (!$order) {
            return redirect()->route('home')->with('error', 'Order not found');
        }
        
        // Verify user owns this order (if logged in)
        if (Auth::check() && $order->user_id != Auth::id()) {
            return redirect()->route('home')->with('error', 'Access denied');
        }
        
        return view('order-confirmation', compact('order'));
    }
    
    /**
     * Test Payment Page (for development)
     */
    public function testPaymentPage()
    {
        return view('test-mpesa');
    }
    
    /**
     * Get transaction history (for logged in users)
     */
    public function myTransactions()
    {
        if (!Auth::check()) {
            return redirect()->route('login')->with('error', 'Please login to view transactions');
        }
        
        $transactions = MpesaTransaction::where('user_id', Auth::id())
            ->orderBy('created_at', 'desc')
            ->paginate(20);
        
        return view('transactions.index', compact('transactions'));
    }
    
    /**
     * View single transaction
     */
    public function viewTransaction($id)
    {
        $transaction = MpesaTransaction::findOrFail($id);
        
        // Check authorization
        if (Auth::check() && $transaction->user_id != Auth::id() && !Auth::user()->isAdmin()) {
            return redirect()->route('home')->with('error', 'Access denied');
        }
        
        return view('transactions.show', compact('transaction'));
    }
}