<?php

namespace App\Http\Controllers;

use App\Models\BkashTransaction;
use App\Models\BkashToken;
use Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class BkashPaymentController extends Controller
{
    private $base_url;
    private $app_key;
    private $app_secret;
    private $username;
    private $password;
    private $callbackURL;
    private $enableURl;

    public function __construct()
    {
        $this->enableURl   = env('BKASH_ENABLE_URL');
        $this->callbackURL = route('execute-bkash-payment');
        $this->app_key     = env('BKASH_APP_KEY');
        $this->app_secret  = env('BKASH_APP_SECRET');
        $this->username    = env('BKASH_USERNAME');
        $this->password    = env('BKASH_PASSWORD');
        $this->base_url    = env('BKASH_BASE_URL');
    }

    public function payment(Request $request)
    {
        $request->validate([
            'amount'     => 'required|numeric|min:1',
            'customer_id'=> 'required',
        ]);
        return $this->makePayment($request->amount, $request->customer_id);
    }

    private function makePayment($amount, $customerId)
    {
        Session::forget('id_token');
        $token = BkashToken::latest()->first();
        if ($token && (strtotime($token->created_at) + 3500) > time()) {
            $idToken = $token->id_token;
        } else {
            $tokenResponse = $this->getToken();
            if (
                !$tokenResponse ||
                !isset($tokenResponse['statusCode'], $tokenResponse['statusMessage']) ||
                $tokenResponse['statusCode'] !== '0000' ||
                $tokenResponse['statusMessage'] !== 'Successful'
            ) {
                return redirect('/')->with('wrong', 'Token generate failed! Try again.');
            }
            BkashToken::create([
                'id_token'      => $tokenResponse['id_token'],
                'token_type'    => $tokenResponse['token_type'],
                'expires_in'    => $tokenResponse['expires_in'],
                'refresh_token' => $tokenResponse['refresh_token'],
            ]);
            $idToken = $tokenResponse['id_token'];
        }
        Session::put('id_token',$idToken);
        $InvoiceNumber = strtoupper('Fast-Net-Communication-Dot-Com-') . rand(1000, 99999);
        $auth = $idToken;
        $requestbody = [
            'mode'                  => '0011',
            'amount'                => $amount,
            'currency'              => 'BDT',
            'intent'                => 'sale',
            'payerReference'        => $customerId,
            'merchantInvoiceNumber' => $InvoiceNumber,
            'callbackURL'           => $this->callbackURL
        ];
        $createurl = $this->base_url . '/tokenized/checkout/create';
        $header = [
            "Content-Type" => "application/json",
            "Authorization" => $auth ,
            "X-APP-Key"=> $this->app_key
        ];
        $createResponse = $this->curlPost($createurl,$requestbody,$header);
        if (!$createResponse || !isset($createResponse['callbackURL'])) {
            Log::error('bKash create payment failed', ['response' => $createResponse]);
            return redirect('/')->with('wrong', 'Payment initiation failed.');
        }
        return redirect($createResponse['bkashURL']);
    }
    
    public function executePayment(Request $request)
    {
        if (!isset($_GET['paymentID'], $_GET['status'])) {
            return "Invalid Request";
        }
        $status = $_GET['status'];
        $paymentID = $_GET['paymentID'];
        
        if ($status !== 'success') {
            $msg = $status === 'failure' ? 'Payment failed!' : 'Payment cancelled.';
            return redirect('/')->with('wrong', $msg);
        }
        
        $data = ['paymentID' => $_GET['paymentID']];
        $executeUrl = $this->base_url . '/tokenized/checkout/execute';
        $header = [
            "Content-Type"=>"application/json",
            "Authorization" => Session::get('id_token'),
            "X-APP-Key" => $this->app_key
        ];
        try {
            $executeResponse = $this->curlPost($executeUrl,$data,$header);
            
            if(!$executeResponse || $executeResponse['statusCode'] !== '0000'){
                Log::error('bKash execute failed', ['response' => $executeResponse]);
                return redirect('/')->with('wrong', $executeResponse['statusMessage'] ?? 'Execution failed');
            }
            if( $executeResponse['transactionStatus'] === 'Completed' || $executeResponse['statusCode'] === '0000'){
                $this->saveAndProcessSuccess($executeResponse);
                return redirect('/')->with('success', 'Your Bkash Payment Successfully complete.');
            }
        } catch (\Exception $e){
            if (str_contains($e->getMessage(), 'timed out')) {
                Log::warning('bKash Execute Timeout', ['paymentID' => $data['paymentID'] ?? '']);
        
                $queryResponse = $this->queryPayment($data['paymentID'] ?? null);
                if( $queryResponse['statusMessage'] === 'Successful' || $queryResponse['statusCode'] === '0000'){
                    $this->saveAndProcessSuccess($queryResponse);
                    return redirect('/')->with('success', 'Your Bkash Payment Successfully complete.');
                }
            }
        }

    }
    
    private function getToken(){
        return $this->curlPost(
                $this->base_url . "/tokenized/checkout/token/grant",
                ['app_key' => $this->app_key,'app_secret' => $this->app_secret],
                [ "Content-Type"=>"application/json", "password"=>$this->password, "username"=>$this->username]
            );
    }
    
    private function curlPost($url,$data, $headers = [], $timeout = 30){
        $ch = curl_init($url);
        $payload = json_encode($data);
        
        $defaultHeaders = [];
        foreach($headers as $k => $v){
            $defaultHeaders[] = "$k: $v";
        }
        
        curl_setopt($ch, CURLOPT_HTTPHEADER, $defaultHeaders);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        $responseData = curl_exec($ch);
        curl_close($ch);
        return json_decode($responseData, true) ?: $responseData;
    }
    
    private function saveAndProcessSuccess($obj){
        
        $bkashTransaction = new BkashTransaction();
        $bkashTransaction->payment_id = $obj['paymentID'];
        $bkashTransaction->type = 'bkashpay';
        $bkashTransaction->currency = $obj['currency'];
        $bkashTransaction->amount = $obj['amount'];
        $bkashTransaction->customer_id = $obj['payerReference'];
        $bkashTransaction->status = $obj['transactionStatus'];
        $bkashTransaction->trx_id = $obj['trxID'];
        $bkashTransaction->merchant_invoice_number = $obj['merchantInvoiceNumber'];
        $bkashTransaction->payment_time = $obj['paymentExecuteTime'];
        $bkashTransaction->mobile = $obj['customerMsisdn'];
        $bkashTransaction->save();
        
        if (Session::get('customer_id')) {
            
            $customer = DB::table('tbl_agent')->where('ag_id', Session::get('customer_id'))->first();
            if (!$customer) {
                Log::error('saveAndProcessSuccess: customer not found for ag_id ' . $obj['payerReference']);
                return; // ba jeta appropriate mone koro
            }
        
            DB::select("SELECT function_bill_update(?,?,?,?,?,?,?,?) as function_bill_update",
                [$customer->ag_id, 'bkash_billpay', $obj['amount'], 1, '', 99, 2, $obj['trxID']]);
        
            try {
                $client = new \GuzzleHttp\Client();
                $client->get($this->enableURl.'/enable.php', [
                    'query' => ['ag_id' => $customer->ag_id, 'amount' => $obj['amount']],
                    'timeout' => 10
                ]);
            } catch (\Exception $e) {
                Log::error('Enable API failed: ' . $e->getMessage());
            }
        
        } elseif (Session::get('reseller_id')) {
        
            $resellerUser = DB::table('_reseller_createuser')
                ->where('UserId', Session::get('reseller_id'))
                ->first();
        
            if (!$resellerUser) {
                Log::error('saveAndProcessSuccess: resellerUser not found for UserId ' . Session::get('reseller_id'));
                return; // ba redirect kore error message dekhao
            }
        
            $newBalanceInput = $obj['amount'] ?? 0;
            $newPaymentInput = $obj['amount'] ?? 0;
        
            $newbal = $resellerUser->balance + $newBalanceInput;
            $newdue = $resellerUser->dueadvance + ($newBalanceInput - $newPaymentInput);
        
            DB::table('_reseller_createuser')
                ->where('UserId', Session::get('reseller_id'))
                ->update(['balance' => $newbal, 'dueadvance' => $newdue]);
        
            DB::table('re_tbl_reseller_account')->insert([
                'admin_id'    => 99,
                'reseller_id' => Session::get('reseller_id'),
                'amount'      => $obj['amount'],
                'type'        => 1,
                'description' => 'bKash balance recharge',
                'remark'      => "remark",
                'entry_by'    => 99,
                'entry_date'  => date('Y-m-d'),
            ]);
        
            $lastracid = DB::table('re_tbl_reseller_account')->insertGetId([
                'admin_id'    => 99,
                'reseller_id' => Session::get('reseller_id'),
                'amount'      => $obj['amount'],
                'type'        => 3,
                'description' => "Payment receive ",
                'remark'      => 'remark',
                'entry_by'    => 99,
                'entry_date'  => date('Y-m-d')
            ]);
        
            DB::table('re_tbl_account')->insert([
                'reseller_account_id' => $lastracid,
                'reseller_id'          => Session::get('reseller_id'),
                'acc_amount'           => $obj['amount'],
                'acc_type'             => 3,
                'acc_description'      => "Payment receive From Reseller",
                'entry_by'             => 99,
                'entry_date'           => date('Y-m-d')
            ]);
            
        } elseif (Session::get('reseller_customer_id')){
            $resellerCustomer = DB::table('re_tbl_agent')
                ->where('ag_id', Session::get('reseller_customer_id'))
                ->first();
                
            if (!$resellerCustomer) {
                Log::error('saveAndProcessSuccess: resellerUser not found for UserId ' . Session::get('reseller_customer_id'));
                return;
            }

             try {
                $client = new \GuzzleHttp\Client();
            
                $url = $this->enableURl . "/pages/resellers/billcollection/bkash_partial_recharge_ajax.php";
                $query = [
                    'token'  => $resellerCustomer->ag_id,
                    'amount' => $obj['amount'],
                ];
            
                $response = $client->get($url, [
                    'query' => $query,
                    'timeout' => 10,
                    'http_errors' => false,
                ]);
            
                $statusCode = $response->getStatusCode();
                $body = (string) $response->getBody();
            
                Log::info('Enable API Response', [
                    'status_code' => $statusCode,
                    'body'        => $body,
                ]);
            
                $decoded = json_decode($body, true);
            
                if (json_last_error() === JSON_ERROR_NONE) {
                    Log::info('Enable API Decoded JSON', $decoded);
                } else {
                    Log::warning('Enable API response is not valid JSON', [
                        'raw_body' => $body
                    ]);
                }
            
            } catch (\GuzzleHttp\Exception\RequestException $e) {
                Log::error('Enable API RequestException', [
                    'message' => $e->getMessage(),
                    'url'     => $this->enableURl . "/pages/resellers/billcollection/bkash_partial_recharge_ajax.php",
                ]);
            
                if ($e->hasResponse()) {
                    Log::error('Enable API Error Response', [
                        'status_code' => $e->getResponse()->getStatusCode(),
                        'body'        => (string) $e->getResponse()->getBody(),
                    ]);
                }
            
            } catch (\Exception $e) {
                Log::error('Enable API General Error', [
                    'message' => $e->getMessage(),
                    'line'    => $e->getLine(),
                    'file'    => $e->getFile(),
                ]);
            }
        }
    }
    public function queryPayment($paymentID)
    {
        $queryUrl = $this->base_url . '/tokenized/checkout/payment/status';
        
        $data = [
            'paymentID' => $paymentID
        ];
    
        $header = [
            "Content-Type" => "application/json",
            "Authorization" => Session::get('id_token'),
            "X-APP-Key" => $this->app_key
        ];
    
        return $this->curlPost($queryUrl, $data, $header, 30);
    }
    
    public function search(Request $request){
        $request->validate([
            'trxID' => 'required|string|max:50'
        ]);
        $trxID = trim($request->trxID);
        $tokenResponse = $this->getToken();
        $auth = $tokenResponse['id_token'];
        $searchUrl = $this->base_url . '/tokenized/checkout/general/searchTransaction';
        $data = [
            'trxID' => $trxID
            ];
        $header = [
            "Content-Type" => "application/json",
            "Authorization" => $auth,
            "X-APP-Key" => $this->app_key
        ];
        $response = $this->curlPost($searchUrl, $data, $header, 30);
        if(isset($response['trxID'])){
            $searchResult = $response;
        }else{
            $searchResult = null;
        }
        return view('home.search-transaction',compact('searchResult'));
    }
    
    
}