<?php

namespace App\Http\Controllers;

use App\Models\Transaction;
use App\Models\Gateway;
use App\Models\ApiKey;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class BkashTokenizedController extends Controller
{
    private function getBaseUrl(array $credentials): string
    {
        $sandbox = $credentials['sandbox'] ?? 'disable';
        return $sandbox === 'enable' 
            ? 'https://tokenized.sandbox.bka.sh/v1.2.0-beta/tokenized/checkout' 
            : 'https://tokenized.pay.bka.sh/v1.2.0-beta/tokenized/checkout';
    }

    private function getHeaders(array $credentials, string $token = null): array
    {
        $headers = [
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'x-app-key' => $credentials['app_key'] ?? '',
        ];

        if ($token) {
            $headers['authorization'] = $token;
        }

        return $headers;
    }

    private function grantToken(array $credentials, string $baseUrl): ?string
    {
        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'Accept' => 'application/json',
                'username' => $credentials['username'] ?? '',
                'password' => $credentials['password'] ?? '',
            ])->post($baseUrl . '/token/grant', [
                'app_key' => $credentials['app_key'] ?? '',
                'app_secret' => $credentials['app_secret'] ?? '',
            ]);

            if ($response->successful()) {
                return $response->json('id_token');
            }

            Log::error('bKash Grant Token Failed: ' . $response->body());
        } catch (\Exception $e) {
            Log::error('bKash Grant Token Exception: ' . $e->getMessage());
        }

        return null;
    }

    public function initiate(Transaction $transaction)
    {
        if ($transaction->status !== 'PENDING') {
            return redirect()->route('checkout.show', $transaction)->with('error', 'Transaction is already processed.');
        }

        $gateway = Gateway::where('name', $transaction->gateway)->first();
        if (!$gateway || empty($gateway->credentials)) {
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'Gateway configuration is missing.');
        }

        $credentials = $gateway->credentials;
        $baseUrl = $this->getBaseUrl($credentials);

        $idToken = $this->grantToken($credentials, $baseUrl);
        if (!$idToken) {
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'Failed to authenticate with bKash API.');
        }

        try {
            $callbackUrl = route('bkash.callback', $transaction);
            
            $response = Http::withHeaders($this->getHeaders($credentials, $idToken))
                ->post($baseUrl . '/payment/create', [
                    'mode' => '0011',
                    'payerReference' => $transaction->reference_id,
                    'callbackURL' => $callbackUrl,
                    'amount' => number_format($transaction->amount, 2, '.', ''),
                    'currency' => 'BDT',
                    'intent' => 'sale',
                    'merchantInvoiceNumber' => $transaction->reference_id,
                ]);

            if ($response->successful() && $response->json('statusCode') === '0000') {
                $paymentId = $response->json('paymentID');
                $bkashUrl = $response->json('bkashURL');

                session([
                    'bkash_payment_id_' . $transaction->id => $paymentId,
                    'bkash_token_' . $transaction->id => $idToken,
                ]);

                return redirect()->away($bkashUrl);
            }

            Log::error('bKash Create Payment Failed: ' . $response->body());
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'bKash Error: ' . ($response->json('statusMessage') ?: 'Failed to create payment.'));
        } catch (\Exception $e) {
            Log::error('bKash Create Payment Exception: ' . $e->getMessage());
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'An error occurred while initiating bKash payment.');
        }
    }

    public function callback(Request $request, Transaction $transaction)
    {
        $status = $request->query('status');
        $paymentId = $request->query('paymentID');

        if ($status !== 'success' || !$paymentId) {
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'Payment was ' . ($status ?: 'cancelled') . '.');
        }

        $gateway = Gateway::where('name', $transaction->gateway)->first();
        if (!$gateway || empty($gateway->credentials)) {
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'Gateway configuration is missing.');
        }

        $credentials = $gateway->credentials;
        $baseUrl = $this->getBaseUrl($credentials);

        $idToken = $this->grantToken($credentials, $baseUrl);
        if (!$idToken) {
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'Failed to authenticate with bKash API.');
        }

        try {
            $response = Http::withHeaders($this->getHeaders($credentials, $idToken))
                ->post($baseUrl . '/payment/execute', [
                    'paymentID' => $paymentId,
                ]);

            if ($response->successful()) {
                $data = $response->json();
                $statusCode = $data['statusCode'] ?? '';
                $trxID = $data['trxID'] ?? '';
                $transactionStatus = $data['transactionStatus'] ?? '';

                if ($statusCode === '0000' && $transactionStatus === 'Completed') {
                    $transaction->update([
                        'status' => 'SUCCESS',
                        'trx_id' => $trxID,
                    ]);

                    // Trigger Webhook
                    $apiKey = ApiKey::where('user_id', $transaction->user_id)->first();
                    if ($apiKey && $apiKey->webhook_url) {
                        try {
                            Http::post($apiKey->webhook_url, [
                                'reference_id' => $transaction->reference_id,
                                'trx_id' => $trxID,
                                'amount' => $transaction->amount,
                                'status' => 'SUCCESS'
                            ]);
                        } catch (\Exception $e) {
                            Log::error('Webhook failed: ' . $e->getMessage());
                        }
                    }

                    return redirect()->route('checkout.show', $transaction)->with('success', 'Payment verified successfully!');
                }

                if ($statusCode === '2023') {
                    $transaction->update([
                        'status' => 'SUCCESS',
                        'trx_id' => $trxID ?: ($data['paymentID'] ?? 'bkash_already_completed'),
                    ]);
                    return redirect()->route('checkout.show', $transaction)->with('info', 'Payment was already processed.');
                }

                Log::error('bKash Execute Payment Error Data: ' . json_encode($data));
                $transaction->update(['gateway' => null]);
                return redirect()->route('checkout.show', $transaction)->with('error', 'bKash Verification Error: ' . ($data['statusMessage'] ?? 'Failed to execute payment.'));
            }

            Log::error('bKash Execute Payment Failed: ' . $response->body());
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'Failed to execute bKash payment.');
        } catch (\Exception $e) {
            Log::error('bKash Execute Payment Exception: ' . $e->getMessage());
            $transaction->update(['gateway' => null]);
            return redirect()->route('checkout.show', $transaction)->with('error', 'An error occurred while executing payment verification.');
        }
    }
}
