<?php

namespace App\Http\Controllers;

use App\Models\Order;
use App\Models\Transaction;
use App\Models\OrderHistory;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Exception;

class PaymentController extends Controller
{
    /**
     * Initiate payment via SSLCommerz.
     */
    public function initiateSSLCommerz(Order $order)
    {
        $storeId = Setting::getValue('sslcommerz_store_id');
        $storePasswd = Setting::getValue('sslcommerz_store_password');
        $isSandbox = Setting::getValue('sslcommerz_sandbox', true);

        if (!$storeId || !$storePasswd) {
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout?error=' . urlencode('SSLCommerz payment is not configured properly.'));
        }

        $baseUrl = $isSandbox 
            ? 'https://sandbox.sslcommerz.com' 
            : 'https://securepay.sslcommerz.com';
        
        $url = $baseUrl . '/gwprocess/v4/api.php';

        $payload = [
            'store_id' => $storeId,
            'store_passwd' => $storePasswd,
            'total_amount' => $order->grand_total,
            'currency' => 'BDT',
            'tran_id' => $order->order_number,
            'success_url' => route('payment.ssl.success'),
            'fail_url' => route('payment.ssl.fail'),
            'cancel_url' => route('payment.ssl.cancel'),
            'ipn_url' => route('payment.ssl.ipn'),
            
            // Customer Info
            'cus_name' => $order->customer_name,
            'cus_email' => $order->customer_email ?? 'customer@example.com',
            'cus_add1' => $order->shipping_address,
            'cus_city' => (function() use ($order) {
                $parts = explode(',', $order->shipping_address);
                if (count($parts) >= 2) {
                    $idx = count($parts) - 2;
                    return trim($parts[$idx]);
                }
                return 'Dhaka';
            })(),
            'cus_country' => 'Bangladesh',
            'cus_phone' => $order->customer_phone,
            
            // Shipment Info
            'shipping_method' => 'YES',
            'num_of_item' => $order->items()->count(),
            'product_name' => 'Order #' . $order->order_number,
            'product_category' => 'E-commerce',
            'product_profile' => 'general',
        ];

        try {
            $response = Http::asForm()->post($url, $payload);
            
            if ($response->failed()) {
                throw new Exception('SSLCommerz server connection failed.');
            }

            $result = $response->json();
            
            if (isset($result['status']) && $result['status'] === 'SUCCESS' && isset($result['GatewayPageURL'])) {
                // Log transaction initiation
                Transaction::create([
                    'order_id' => $order->id,
                    'transaction_id' => $order->order_number,
                    'payment_method' => 'sslcommerz',
                    'amount' => $order->grand_total,
                    'status' => 'pending',
                    'raw_response' => $result,
                ]);

                return redirect()->away($result['GatewayPageURL']);
            }

            Log::error('SSLCommerz initiation failed: ' . json_encode($result));
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('Failed to connect to SSLCommerz Gateway: ' . ($result['failedreason'] ?? 'Unknown error')));
        } catch (Exception $e) {
            Log::error('SSLCommerz initiation exception: ' . $e->getMessage());
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('Payment Connection Error: ' . $e->getMessage()));
        }
    }

    /**
     * SSLCommerz success callback.
     */
    public function sslSuccess(Request $request)
    {
        $tranId = $request->input('tran_id');
        $valId = $request->input('val_id');
        $amount = $request->input('amount');

        Log::info('SSLCommerz Success Callback received for ID: ' . $tranId);

        $order = Order::where('order_number', $tranId)->first();

        if (!$order) {
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/shop?error=' . urlencode('Matching order not found for payment.'));
        }

        // Validate transaction using SSLCommerz Validation API
        $isSandbox = Setting::getValue('sslcommerz_sandbox', true);
        $storeId = Setting::getValue('sslcommerz_store_id');
        $storePasswd = Setting::getValue('sslcommerz_store_password');

        $baseUrl = $isSandbox 
            ? 'https://sandbox.sslcommerz.com' 
            : 'https://securepay.sslcommerz.com';
        
        $validationUrl = $baseUrl . '/validator/api/validationserverAPI.php';

        $response = Http::get($validationUrl, [
            'val_id' => $valId,
            'store_id' => $storeId,
            'store_passwd' => $storePasswd,
            'format' => 'json'
        ]);

        if ($response->successful()) {
            $result = $response->json();
            
            if (isset($result['status']) && ($result['status'] === 'VALID' || $result['status'] === 'VALIDATED')) {
                // Securely mark order as Paid
                $this->markOrderAsPaid($order, $result, 'sslcommerz');
                
                return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/success/' . $order->id);
            }
        }

        // Log validation failed
        Log::error('SSLCommerz Transaction validation failed for #' . $order->order_number);
        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('Payment verification failed.'));
    }

    /**
     * SSLCommerz fail callback.
     */
    public function sslFail(Request $request)
    {
        $tranId = $request->input('tran_id');
        Log::warning('SSLCommerz payment failed for transaction #' . $tranId);
        
        $order = Order::where('order_number', $tranId)->first();
        if ($order) {
            $oldStatus = $order->payment_status;
            $order->update(['payment_status' => 'failed']);
            Transaction::where('transaction_id', $tranId)->update(['status' => 'failed', 'raw_response' => $request->all()]);
            
            if ($oldStatus !== 'failed') {
                try {
                    \App\Services\NotificationDispatcher::dispatchPaymentFailed($order);
                } catch (\Exception $e) {
                    Log::error('Failed to dispatch payment failed notification: ' . $e->getMessage());
                }
            }
        }

        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('Payment failed or was declined.'));
    }

    /**
     * SSLCommerz cancel callback.
     */
    public function sslCancel(Request $request)
    {
        $tranId = $request->input('tran_id');
        Log::info('SSLCommerz payment cancelled for transaction #' . $tranId);
        
        $order = Order::where('order_number', $tranId)->first();
        if ($order) {
            $oldStatus = $order->payment_status;
            $order->update(['payment_status' => 'failed']);
            Transaction::where('transaction_id', $tranId)->update(['status' => 'cancelled', 'raw_response' => $request->all()]);
            
            if ($oldStatus !== 'failed') {
                try {
                    \App\Services\NotificationDispatcher::dispatchPaymentFailed($order);
                } catch (\Exception $e) {
                    Log::error('Failed to dispatch payment failed notification: ' . $e->getMessage());
                }
            }
        }

        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('Payment was cancelled.'));
    }

    /**
     * SSLCommerz IPN webhook.
     */
    public function sslIpn(Request $request)
    {
        $tranId = $request->input('tran_id');
        $valId = $request->input('val_id');
        
        Log::info('SSLCommerz IPN received for Transaction #' . $tranId);

        $order = Order::where('order_number', $tranId)->first();

        if ($order && strtolower($order->payment_status) !== 'paid') {
            $isSandbox = Setting::getValue('sslcommerz_sandbox', true);
            $storeId = Setting::getValue('sslcommerz_store_id');
            $storePasswd = Setting::getValue('sslcommerz_store_password');

            $baseUrl = $isSandbox 
                ? 'https://sandbox.sslcommerz.com' 
                : 'https://securepay.sslcommerz.com';
            
            $validationUrl = $baseUrl . '/validator/api/validationserverAPI.php';

            $response = Http::get($validationUrl, [
                'val_id' => $valId,
                'store_id' => $storeId,
                'store_passwd' => $storePasswd,
                'format' => 'json'
            ]);

            if ($response->successful()) {
                $result = $response->json();
                if (isset($result['status']) && ($result['status'] === 'VALID' || $result['status'] === 'VALIDATED')) {
                    $this->markOrderAsPaid($order, $result, 'sslcommerz');
                    return response()->json(['status' => 'success', 'message' => 'IPN processed.']);
                }
            }
        }

        return response()->json(['status' => 'ignored']);
    }

    /**
     * Initiate payment via bKash Checkout.
     */
    public function initiatebKash(Order $order)
    {
        $username = Setting::getValue('bkash_username');
        $password = Setting::getValue('bkash_password');
        $appKey = Setting::getValue('bkash_app_key');
        $appSecret = Setting::getValue('bkash_app_secret');
        $isSandbox = Setting::getValue('bkash_sandbox', true);

        if (!$username || !$password || !$appKey || !$appSecret) {
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout?error=' . urlencode('bKash payment credentials are not configured.'));
        }

        $baseUrl = $isSandbox 
            ? 'https://tokenized.sandbox.bka.sh/v1.2.0-beta' 
            : 'https://tokenized.pay.bka.sh/v1.2.0-beta';

        try {
            // 1. Get Access Token
            $authResponse = Http::withHeaders([
                'username' => $username,
                'password' => $password,
            ])->post($baseUrl . '/tokenized/checkout/token/grant', [
                'app_key' => $appKey,
                'app_secret' => $appSecret,
            ]);

            if ($authResponse->failed()) {
                throw new Exception('bKash auth token request failed: ' . ($authResponse->json('errorMessage') ?? 'Connection Error'));
            }

            $idToken = $authResponse->json('id_token');

            // 2. Create Payment
            $createResponse = Http::withHeaders([
                'Authorization' => $idToken,
                'X-APP-Key' => $appKey,
            ])->post($baseUrl . '/tokenized/checkout/payment/create', [
                'mode' => '0011',
                'payerReference' => $order->customer_phone,
                'callbackURL' => route('payment.bkash.callback', ['order' => $order->id]),
                'amount' => $order->grand_total,
                'currency' => 'BDT',
                'intent' => 'sale',
                'merchantInvoiceNumber' => $order->order_number,
            ]);

            if ($createResponse->failed()) {
                throw new Exception('bKash payment creation failed: ' . ($createResponse->json('errorMessage') ?? 'Gateway Error'));
            }

            $result = $createResponse->json();

            if (isset($result['statusCode']) && $result['statusCode'] === '0000' && isset($result['bkashURL'])) {
                // Log transaction initiation
                Transaction::create([
                    'order_id' => $order->id,
                    'transaction_id' => $result['paymentID'],
                    'payment_method' => 'bkash',
                    'amount' => $order->grand_total,
                    'status' => 'pending',
                    'raw_response' => $result,
                ]);

                // Save bKash token & paymentID temporarily in session or db
                session(['bkash_token' => $idToken, 'bkash_payment_id' => $result['paymentID']]);

                return redirect()->away($result['bkashURL']);
            }

            throw new Exception($result['errorMessage'] ?? 'Unknown bKash error.');
        } catch (Exception $e) {
            Log::error('bKash payment initiation error: ' . $e->getMessage());
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('bKash Connection Error: ' . $e->getMessage()));
        }
    }

    /**
     * bKash Callback routing.
     */
    public function bkashCallback(Request $request, Order $order)
    {
        $status = $request->query('status');
        $paymentId = $request->query('paymentID');
        
        $idToken = session('bkash_token');
        $storedPaymentId = session('bkash_payment_id');

        Log::info('bKash Callback status: ' . $status . ' for payment ID: ' . $paymentId);

        if ($status === 'success' && $paymentId === $storedPaymentId && $idToken) {
            $username = Setting::getValue('bkash_username');
            $password = Setting::getValue('bkash_password');
            $appKey = Setting::getValue('bkash_app_key');
            $appSecret = Setting::getValue('bkash_app_secret');
            $isSandbox = Setting::getValue('bkash_sandbox', true);

            $baseUrl = $isSandbox 
                ? 'https://tokenized.sandbox.bka.sh/v1.2.0-beta' 
                : 'https://tokenized.pay.bka.sh/v1.2.0-beta';

            try {
                // Execute Payment API
                $executeResponse = Http::withHeaders([
                    'Authorization' => $idToken,
                    'X-APP-Key' => $appKey,
                ])->post($baseUrl . '/tokenized/checkout/payment/execute', [
                    'paymentID' => $paymentId,
                ]);

                $result = $executeResponse->json();

                if (isset($result['statusCode']) && $result['statusCode'] === '0000') {
                    // Mark order as Paid
                    $this->markOrderAsPaid($order, $result, 'bkash');
                    
                    return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/success/' . $order->id);
                }

                Log::error('bKash Execution Error: ' . json_encode($result));
                return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode($result['errorMessage'] ?? 'Unknown Error'));
            } catch (Exception $e) {
                Log::error('bKash execution exception: ' . $e->getMessage());
                return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('bKash Callback Verification error: ' . $e->getMessage()));
            }
        }

        // Cancelled or Failed
        $oldStatus = $order->payment_status;
        $order->update(['payment_status' => 'failed']);
        Transaction::where('transaction_id', $paymentId)->update(['status' => 'failed', 'raw_response' => $request->all()]);
        
        if ($oldStatus !== 'failed') {
            try {
                \App\Services\NotificationDispatcher::dispatchPaymentFailed($order);
            } catch (\Exception $e) {
                Log::error('Failed to dispatch payment failed notification: ' . $e->getMessage());
            }
        }

        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed/' . $order->id . '?error=' . urlencode('bKash payment was ' . $status . ' or validation failed.'));
    }

    /**
     * Helper to mark order as paid, create transaction audits, and logging logs.
     */
    private function markOrderAsPaid(Order $order, array $gatewayResponse, string $method)
    {
        $oldPaymentStatus = $order->payment_status;
        
        $order->update([
            'payment_status' => 'paid',
            'payment_method' => $method,
            'status' => 'processing', // Move to processing once paid
        ]);

        $tranId = $gatewayResponse['tran_id'] ?? ($gatewayResponse['paymentID'] ?? $order->order_number);

        // Update or create transaction record
        Transaction::updateOrCreate(
            ['order_id' => $order->id, 'transaction_id' => $tranId],
            [
                'payment_method' => $method,
                'amount' => $order->grand_total,
                'status' => 'success',
                'raw_response' => $gatewayResponse,
            ]
        );

        // Record history logs
        OrderHistory::create([
            'order_id' => $order->id,
            'user_id' => auth()->check() ? auth()->id() : null,
            'action' => 'payment_received',
            'from_status' => $oldPaymentStatus,
            'to_status' => 'paid',
            'notes' => 'Received ' . $order->grand_total . ' BDT via ' . strtoupper($method) . '. Gateway Ref: ' . ($gatewayResponse['bank_tran_id'] ?? ($gatewayResponse['trxID'] ?? 'N/A')),
        ]);

        // Dispatch notifications if this is the transition to paid
        if ($oldPaymentStatus !== 'paid') {
            try {
                \App\Services\NotificationDispatcher::dispatchPaymentReceived($order);
                \App\Services\NotificationDispatcher::dispatchOrderPlaced($order);
            } catch (\Exception $e) {
                Log::error('Failed to send payment success notification for #' . $order->order_number . ': ' . $e->getMessage());
            }
        }
    }

    /**
     * Retry payment for an unpaid order.
     */
    /**
     * Initiate payment via Nagad Checkout.
     */
    public function initiateNagad(Order $order)
    {
        $merchantId = Setting::getValue('nagad_merchant_id');
        $privateKey = Setting::getValue('nagad_merchant_private_key');
        $publicKey = Setting::getValue('nagad_public_key');
        $isSandbox = Setting::getValue('nagad_sandbox', true);

        if (!$merchantId || !$privateKey || !$publicKey) {
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout?error=' . urlencode('Nagad payment credentials are not configured.'));
        }

        // For testing/sandbox, immediately redirect to callback to mock success
        if ($isSandbox) {
            return redirect()->route('payment.nagad.callback', ['order' => $order->id, 'status' => 'success']);
        }

        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout?error=' . urlencode('Nagad live integration is running in sandbox mock mode.'));
    }

    /**
     * Nagad payment callback handler.
     */
    public function nagadCallback(Request $request, Order $order)
    {
        $status = $request->query('status');

        if ($status === 'success') {
            $order->update([
                'payment_status' => 'paid',
                'notes' => $order->notes . ' | Payment verified successfully via Nagad (Sandbox).',
            ]);

            try {
                \App\Services\NotificationDispatcher::dispatchOrderPlaced($order);
            } catch (\Exception $e) {
                Log::error('Failed to send Nagad order placed notification: ' . $e->getMessage());
            }

            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/success/' . $order->id);
        }

        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/failed?orderId=' . $order->id);
    }

    public function retryPayment(Order $order, Request $request)
    {
        if ($order->payment_status === 'paid') {
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/dashboard?success=' . urlencode('Order has already been paid.'));
        }

        $method = $request->query('method', $order->payment_method);
        if (in_array($method, ['sslcommerz', 'bkash', 'cod', 'nagad'])) {
            $order->update(['payment_method' => $method]);
        }

        if ($order->payment_method === 'cod') {
            $order->update(['payment_status' => 'pending']);
            try {
                \App\Services\NotificationDispatcher::dispatchOrderPlaced($order);
            } catch (\Exception $e) {
                Log::error('Failed to dispatch notification on COD retry: ' . $e->getMessage());
            }
            return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/checkout/success/' . $order->id);
        }

        if ($order->payment_method === 'sslcommerz') {
            return redirect()->route('payment.ssl.initiate', ['order' => $order->id]);
        } elseif ($order->payment_method === 'bkash') {
            return redirect()->route('payment.bkash.initiate', ['order' => $order->id]);
        } elseif ($order->payment_method === 'nagad') {
            return redirect()->route('payment.nagad.initiate', ['order' => $order->id]);
        }

        return redirect()->away(env('NEXTJS_FRONTEND_URL', 'http://localhost:3000') . '/dashboard?error=' . urlencode('Payment retry not supported.'));
    }
}
