<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Validator;
use App\Traits\Processor;
use App\Models\PaymentRequest;

class BkashPaymentController extends Controller
{
    use Processor;

    private $config_values;
    private $base_url;
    private $app_key;
    private $app_secret;
    private $username;
    private $password;
    private PaymentRequest $payment;
    private $user;

    public function __construct(PaymentRequest $payment, User $user)
    {
        $config = $this->payment_config('bkash', 'payment_config');

        if (!is_null($config)) {
            if ($config->mode == 'live') {
                $this->config_values = json_decode($config->live_values);
            } else {
                // default to test values for any other mode
                $this->config_values = json_decode($config->test_values);
            }

            if ($this->config_values) {
                $this->app_key    = $this->config_values->app_key    ?? null;
                $this->app_secret = $this->config_values->app_secret ?? null;
                $this->username   = $this->config_values->username   ?? null;
                $this->password   = $this->config_values->password   ?? null;
                $this->base_url   = ($config->mode == 'live')
                    ? 'https://tokenized.pay.bka.sh/v1.2.0-beta'
                    : 'https://tokenized.sandbox.bka.sh/v1.2.0-beta';
            }
        }

        $this->payment = $payment;
        $this->user    = $user;
    }

    public function getToken()
    {
        $post_token = array(
            'app_key' => $this->app_key,
            'app_secret' => $this->app_secret
        );

        $url = curl_init($this->base_url . '/tokenized/checkout/token/grant');
        $post_token_json = json_encode($post_token);
        $header = array(
            'Content-Type:application/json',
            'username:' . $this->username,
            'password:' . $this->password
        );

        curl_setopt($url, CURLOPT_HTTPHEADER, $header);
        curl_setopt($url, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($url, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($url, CURLOPT_POSTFIELDS, $post_token_json);
        curl_setopt($url, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($url, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

        $resultdata = curl_exec($url);
        curl_close($url);

        $response = json_decode($resultdata, true);

        if (array_key_exists('msg', $response)) {
            return $response;
        }

        return $response;
    }

    public function make_tokenize_payment(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'payment_id' => 'required|uuid'
        ]);

        if ($validator->fails()) {
            return response()->json($this->response_formatter(GATEWAYS_DEFAULT_400, null, $this->error_processor($validator)), 400);
        }

        $data = $this->payment::where(['id' => $request['payment_id']])->where(['is_paid' => 0])->first();
        if (!isset($data)) {
            return response()->json($this->response_formatter(GATEWAYS_DEFAULT_204), 200);
        }
        $payer = json_decode($data['payer_information']);

        $response = self::getToken();

        if (empty($response['id_token'])) {
            $msg = $response['msg'] ?? ($response['statusMessage'] ?? 'bKash token error');
            return response()->json(['errors' => ['code' => 'bkash-token', 'message' => $msg]], 500);
        }

        $auth = $response['id_token'];
        session()->put('token', $auth);
        $callbackURL = route('bkash.callback', ['payment_id' => $request['payment_id'], 'token' => $auth]);

        $requestbody = [
            'mode'                  => '0011',
            'amount'                => (string) round($data->payment_amount, 2),
            'currency'              => 'BDT',
            'intent'                => 'sale',
            'payerReference'        => $payer->phone ?? '',
            'merchantInvoiceNumber' => 'invoice_' . Str::random(15),
            'callbackURL'           => $callbackURL,
        ];

        $url = curl_init($this->base_url . '/tokenized/checkout/create');
        $requestbodyJson = json_encode($requestbody);

        $header = [
            'Content-Type:application/json',
            'Authorization:' . $auth,
            'X-APP-Key:' . $this->app_key,
        ];

        curl_setopt($url, CURLOPT_HTTPHEADER, $header);
        curl_setopt($url, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($url, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($url, CURLOPT_POSTFIELDS, $requestbodyJson);
        curl_setopt($url, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($url, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        $resultdata = curl_exec($url);
        curl_close($url);

        $obj = json_decode($resultdata);

        if (empty($obj->bkashURL)) {
            $msg = $obj->statusMessage ?? ($obj->errorMessage ?? 'bKash payment initiation failed');
            return response()->json(['errors' => ['code' => 'bkash-create', 'message' => $msg]], 500);
        }

        return redirect()->away($obj->bkashURL);
    }

    public function callback(Request $request)
    {
        $payment_data = $this->payment::where(['id' => $request['payment_id']])->first();
        $paymentID = $request->query('paymentID');
        $auth = $request->query('token');

        if (!$payment_data) {
            return response()->json($this->response_formatter(GATEWAYS_DEFAULT_204), 200);
        }

        if (!$paymentID || !$auth || $request->query('status') === 'failure' || $request->query('status') === 'cancel') {
            if (function_exists($payment_data->failure_hook)) {
                call_user_func($payment_data->failure_hook, $payment_data);
            }

            return $this->payment_response($payment_data, 'fail');
        }

        $request_body = array(
            'paymentID' => $paymentID
        );
        $url = curl_init($this->base_url . '/tokenized/checkout/execute');

        $request_body_json = json_encode($request_body);

        $header = array(
            'Content-Type:application/json',
            'Authorization:' . $auth,
            'X-APP-Key:' . $this->app_key
        );

        curl_setopt($url, CURLOPT_HTTPHEADER, $header);
        curl_setopt($url, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($url, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($url, CURLOPT_POSTFIELDS, $request_body_json);
        curl_setopt($url, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($url, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        $resultdata = curl_exec($url);
        curl_close($url);
        $obj = json_decode($resultdata);

        if (($obj->statusCode ?? null) == '0000') {

            $this->payment::where(['id' => $request['payment_id']])->update([
                'payment_method' => 'bkash',
                'is_paid' => 1,
                'transaction_id' => $obj->trxID ?? null,
            ]);

            $data = $this->payment::where(['id' => $request['payment_id']])->first();

            if (isset($data) && function_exists($data->success_hook)) {
                call_user_func($data->success_hook, $data);
            }

            return $this->payment_response($data,'success');
        } else {
            if (isset($payment_data) && function_exists($payment_data->failure_hook)) {
                call_user_func($payment_data->failure_hook, $payment_data);
            }
            return $this->payment_response($payment_data,'fail');
        }
    }


}
