<?php

namespace App\Services\Payments\Gateways;

use App\Services\Payments\PaymentGatewayInterface;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Exception;

class BkashGateway implements PaymentGatewayInterface
{
    protected $appKey;
    protected $appSecret;
    protected $username;
    protected $password;
    protected $baseUrl;
    protected $mode;

    public function __construct($config, $mode)
    {
        $this->mode = $mode;
        $credentials = ($mode === 'live') ? $config['live_credentials'] : $config['test_credentials'];
        
        $this->appKey = $credentials['app_key'] ?? '';
        $this->appSecret = $credentials['app_secret'] ?? '';
        $this->username = $credentials['username'] ?? '';
        $this->password = $credentials['password'] ?? '';
        
        $this->baseUrl = ($mode === 'live') 
            ? 'https://tokenized.pay.bka.sh/v1.2.0-beta' 
            : 'https://tokenized.sandbox.bka.sh/v1.2.0-beta';
    }

    /**
     * Get bKash Auth Token (Cached for 50 minutes)
     */
    private function getToken()
    {
        if (empty($this->appKey)) {
            throw new Exception("bKash credentials missing.");
        }

        return Cache::remember("bkash_token_{$this->mode}", 3000, function () {
            $response = Http::withHeaders([
                'username' => $this->username,
                'password' => $this->password,
            ])->post("{$this->baseUrl}/tokenized/checkout/token/grant", [
                'app_key' => $this->appKey,
                'app_secret' => $this->appSecret,
            ]);

            if ($response->failed() || !isset($response->json()['id_token'])) {
                throw new Exception("bKash Token Generation Failed.");
            }

            return $response->json()['id_token'];
        });
    }

    public function pay(float $amount, string $currency, array $metadata)
    {
        if (strtoupper($currency) !== 'BDT') {
            throw new Exception("bKash only supports BDT.");
        }

        $orderNumber = $metadata['order_number']; // Dynamic Order Number from Controller
        $token = $this->getToken();

        $response = Http::withToken($token)->withHeaders([
            'x-app-key' => $this->appKey,
        ])->post("{$this->baseUrl}/tokenized/checkout/create", [
            'mode' => '0011',
            'payerReference' => (string) ($metadata['user_id'] ?? '1'),
            // We pass the order number in the URL so it comes back to our verify() method
            'callbackURL' => route('payment.callback', ['gateway' => 'bkash', 'order' => $orderNumber]),
            'amount' => number_format($amount, 2, '.', ''),
            'currency' => 'BDT',
            'intent' => 'sale',
            'merchantInvoiceNumber' => $orderNumber,
        ]);

        if ($response->successful() && isset($response->json()['bkashURL'])) {
            return ['url' => $response->json()['bkashURL']];
        }

        throw new Exception("bKash Payment Creation Failed: " . ($response->json('statusMessage') ?? $response->body()));
    }

    /**
     * verify returns ['success' => bool, 'order_number' => string]
     */
    public function verify(array $requestData): array
    {
        $orderNumber = $requestData['order'] ?? null;
        $status = $requestData['status'] ?? null;
        $paymentID = $requestData['paymentID'] ?? null;

        // 1. Initial check for success status from bKash redirect
        if ($status !== 'success' || !$paymentID) {
            return [
                'success' => false,
                'order_number' => $orderNumber
            ];
        }

        // 2. Execute the payment to finalize the transaction securely
        $token = $this->getToken();

        try {
            $response = Http::withToken($token)->withHeaders([
                'x-app-key' => $this->appKey,
            ])->post("{$this->baseUrl}/tokenized/checkout/execute", [
                'paymentID' => $paymentID
            ]);

            if ($response->successful()) {
                $data = $response->json();
                
                // bKash statusCode '0000' means successful execution
                $isSuccessful = isset($data['statusCode']) && 
                                $data['statusCode'] === '0000' && 
                                isset($data['transactionStatus']) && 
                                $data['transactionStatus'] === 'Completed';

                return [
                    'success' => $isSuccessful,
                    'order_number' => $orderNumber
                ];
            }
        } catch (\Exception $e) {
            // Log error if necessary
        }

        return [
            'success' => false,
            'order_number' => $orderNumber
        ];
    }
}