<?php

namespace App\Http\Controllers;

use App\Classes\SMS\PaymentSms;
use App\Http\Controllers\Customer\CustomerFrontController;
use App\Jobs\ClientSyncJobForSingle;
use App\Jobs\SendPaymentMailJob;
use App\Models\Billpayment;
use App\Models\Client;
use App\Models\CustomerAccount;
use App\Models\Employee;
use App\Models\Income;
use App\Models\User;
use Brian2694\Toastr\Facades\Toastr;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class EpsController extends Controller
{
    private $baseUrl;
    private $userName;
    private $password;
    private $deviceTypeId;
    private $hashkey;
    private $merchent_id;
    private $store_id;
    private $callbackurl;

    public function __construct()
    {
        // $this->baseUrl = 'https://sandboxpgapi.eps.com.bd';
        // $this->userName = 'Epsdemo@gmail.com';
        // $this->password = 'Epsdemo258@';
        // $this->deviceTypeId = 1;
        // $this->hashkey = 'FHZxyzeps56789gfhg678ygu876o=';
        // $this->merchent_id = '29e86e70-0ac6-45eb-ba04-9fcb0aaed12a';
        // $this->store_id = 'd44e705f-9e3a-41de-98b1-1674631637da';

        $this->baseUrl          = config('app.EPS_BASE_URL');
        $this->userName         = config('app.EPS_USERNAME');
        $this->password         = config('app.EPS_PASSWORD');
        $this->deviceTypeId     = config('app.EPS_DEVICE_TYPE_ID');
        $this->hashkey          = config('app.EPS_HASH_KEY');
        $this->merchent_id      = config('app.EPS_MERCHANT_ID');
        $this->store_id         = config('app.EPS_STORE_ID');
        $this->callbackurl      = config('app.EPS_CALLBACK_URL');
    }

    public function GenerateHash($payload, $hashkey)
    {
        $utf8_key = utf8_encode($hashkey);
        $utf8_payload = utf8_encode($payload);
        $data = hash_hmac('sha512', $utf8_payload, $utf8_key, true);
        $hmac = base64_encode($data);
        return $hmac;
    }

    public function GetToken()
    {
        $curl = curl_init();
        $req_body = array(
            "userName" => $this->userName,
            "password" => $this->password
        );
        $x_hash = $this->GenerateHash($this->userName, $this->hashkey);

        curl_setopt_array($curl, array(
            CURLOPT_URL => $this->baseUrl . '/v1/Auth/GetToken',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => json_encode($req_body),
            CURLOPT_HTTPHEADER => array(
                "x-hash: $x_hash",
                "Content-Type: application/json"
            ),
        ));

        $response = curl_exec($curl);

        if ($response === false) {
            $error = curl_error($curl);
            $info = curl_getinfo($curl);
            die("cURL request failed, error = {$error}; info = " . print_r($info, true));
        }

        $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        if ($responseCode >= 400) {
            die("HTTP Error in gettoken: " . $responseCode);
        }
        curl_close($curl);
        return json_decode($response);
    }

    public function createPayment($payload = array())
    {
        // dd($payload, 'its me');
        try {
            $getToken_response = $this->GetToken();
            if (!isset($getToken_response->token)) {
                die("Access Denied!");
            }

            $curl = curl_init();
            $invoice_id = (string)time();
            $req_body = array(
                "deviceTypeId" => $this->deviceTypeId,
                "merchantId" => $this->merchent_id,
                "storeId" => $this->store_id,
                "transactionTypeId" => 1,
                "financialEntityId" => 0,
                "version" => "1",
                "transactionDate" => date('c'),
                "transitionStatusId" => 0,
                "valueD" => "",
                "merchantTransactionId" => $invoice_id,
            );

            $req_body = array_merge($req_body, $payload);
            // $req_body = array_merge($req_body, (array) $payload);

            $x_hash = $this->GenerateHash($invoice_id, $this->hashkey);
            $token = $getToken_response->token;

            curl_setopt_array($curl, array(
                CURLOPT_URL => $this->baseUrl . '/v1/EPSEngine/InitializeEPS',
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_ENCODING => '',
                CURLOPT_MAXREDIRS => 10,
                CURLOPT_TIMEOUT => 0,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                CURLOPT_CUSTOMREQUEST => 'POST',
                CURLOPT_POSTFIELDS => json_encode($req_body),
                CURLOPT_HTTPHEADER => array(
                    "x-hash: $x_hash",
                    "Authorization: Bearer $token",
                    "Content-Type: application/json"
                ),
            ));

            $response = curl_exec($curl);

            if ($response === false) {
                $error = curl_error($curl);
                $info = curl_getinfo($curl);
                die("cURL request failed, error = {$error}; info = " . print_r($info, true));
            }

            $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

            if ($responseCode >= 400) {
                die("HTTP Error in gettoken: " . $responseCode);
            }
            curl_close($curl);

            return json_decode($response);
        } catch (Exception $e) {
            print_r($e);
        }
    }

    //check payment status...
    public function CheckPaymentStatus($invoice_id)
    {
        // dd($invoice_id, 'its me');
        $getToken_response = $this->GetToken();
        if (!isset($getToken_response->token)) {
            die("Access Denied!");
        }

        $req_body = array(
            "merchantTransactionId" => $invoice_id,
        );

        $curl = curl_init();
        $x_hash = $this->GenerateHash($invoice_id, $this->hashkey);
        $token = $getToken_response->token;

        curl_setopt_array($curl, array(
            CURLOPT_URL => $this->baseUrl . '/v1/EPSEngine/CheckMerchantTransactionStatus?merchantTransactionId=' . $invoice_id,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_POSTFIELDS => json_encode($req_body),
            CURLOPT_HTTPHEADER => array(
                "x-hash: $x_hash",
                "Authorization: Bearer $token",
                "Content-Type: application/json"
            ),
        ));

        $response = curl_exec($curl);

        if ($response === false) {
            $error = curl_error($curl);
            $info = curl_getinfo($curl);
            die("cURL request failed, error = {$error}; info = " . print_r($info, true));
        }

        $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        if ($responseCode >= 400) {
            die("HTTP Error in gettoken: " . $responseCode);
        }
        curl_close($curl);
        return json_decode($response);
    }

    public function epsPayViaAjax(Request $request)
    {
        $info = (array) $request->all();

        $product_arr = array(
            array("ProductName" => "P1", "NoOfItem" => "1", "ProductProfile" => "p1", "ProductCategory" => "PC", "ProductPrice" => $info['amount']),
        );

        $post_data = array();
        $post_data['totalAmount'] = $info['amount'];
        $post_data['CustomerOrderId'] = 'EPS' . uniqid(); // CustomerOrderId must be unique
        $post_data['storeId'] =  $this->store_id;
        $post_data['merchantTransactionId'] =  (string)time(); // merchantTransactionId must be unique

        $post_data['ipAddress'] = "127.0.0.1";
        $post_data['successUrl'] = route('epsSuccess');
        $post_data['failUrl'] = route('epsFailed');
        $post_data['cancelUrl'] = route('epsCancelled');

        $post_data['customerName'] = $info['cus_name'];
        $post_data['customerEmail'] = $info['cus_email'];
        $post_data['customerAddress'] = $info['cus_addr1'];
        $post_data['customerAddress2'] = "";
        $post_data['customerCity'] = "";
        $post_data['customerState'] = "";
        $post_data['customerPostcode'] = "";
        $post_data['customerCountry'] = "Bangladesh";
        $post_data['customerPhone'] = $info['cus_phone'];

        $post_data['shipmentName'] = "Store Test";
        $post_data['shipmentAddress'] = "Dhaka";
        $post_data['shipmentAddress2'] = "Dhaka";
        $post_data['shipmentCity'] = "Dhaka";
        $post_data['shipmentState'] = "Dhaka";
        $post_data['shipmentPostcode'] = "1000";
        $post_data['shipmentCountry'] = "Bangladesh";
        $post_data['shippingMethod'] = "Home Delivery";

        $post_data['valueA'] = $info['customer_id'];
        $post_data['valueB'] = "local_transaction_id";
        $post_data['valueC'] = "order_id-123678";

        $post_data['ProductList'] = $product_arr;

        $update_product = DB::table('orders')
            ->where('transaction_id', $post_data['merchantTransactionId'])
            ->updateOrInsert([
                'name' => $post_data['customerName'],
                'email' => $post_data['customerEmail'],
                'phone' => $post_data['customerPhone'],
                'amount' => $post_data['totalAmount'],
                'status' => 'Pending',
                'address' => $post_data['customerAddress'],
                'transaction_id' => $post_data['merchantTransactionId'],
                'currency' => "BDT",
                'customer_id' => $post_data['valueA'],
                'created_at' => now(),
                'updated_at' => now()
            ]);

        $payment_options = $this->createPayment($post_data);

        try {
            $new_post_data = json_encode($payment_options);
            DB::table('orders')
                ->where('transaction_id', $post_data['merchantTransactionId'])
                ->update(['post_data' => $new_post_data]);
        } catch (\Exception $e) {
        }

        return response()->json($payment_options);
    }

    public function epsSuccess(Request $request)
    {
        $info = (array) $request->all();
        $invoice_id = $info['MerchantTransactionId'];

        $post_data = json_encode($request->all());
        try {
            $update_order_page = DB::table('orders')
                ->where('transaction_id', $invoice_id)
                ->update(['post_data' => $post_data]);

            if (isset($request['EPSTransactionId_']) && $request['EPSTransactionId_'] != null) {
                DB::table('orders')
                    ->where('transaction_id', $invoice_id)
                    ->update(['val_id' => $request['EPSTransactionId_']]);
            }

            $order_detials = DB::table('orders')
                ->where('transaction_id', $invoice_id)
                ->select('transaction_id', 'status', 'currency', 'amount')->first();
        } catch (\Exception $e) {
        }

        $payment_status = $this->CheckPaymentStatus($invoice_id);
        // dd($payment_status);

        // if ($payment_status->Status == 'Success') {
        //     $update_product = DB::table('orders')
        //         ->where('transaction_id', $invoice_id)
        //         ->update([
        //             'status' => 'Success',
        //             'updated_at' => now()
        //         ]);
        // }
        // return response()->json($payment_status);

        if ($payment_status->Status == 'Success') {
            $update_product = DB::table('orders')
                ->where('transaction_id', $invoice_id)
                ->update([
                    'status' => 'Processing',
                    'updated_at' => now()
                ]);
            DB::beginTransaction();
            try {
                $paymentArray = json_decode(json_encode($payment_status), true);
                $request = new Request($paymentArray);
                $status = $this->epsBillPayment($request);

                DB::commit();
            } catch (\Exception $e) {
                Log::error("error in eps payment");
            }
            // CustomerFrontController::getinfo($request);
            Toastr::success('Payment Successfull', 'Success');
            return redirect()->route('customerDashboard');
        } else {
            $update_product = DB::table('orders')
                ->where('transaction_id', $invoice_id)
                ->update(['status' => 'Failed']);
            return redirect()->route('customerDashboard')->with('error_message', 'Validation Faild');
        }
    }

    public function epsBillPayment(Request $request)
    {
        $gateway = 'EPSGateway';
        $info = array(
            'customer_id'    => $request->ValueA,
            'amount'         => $request->TotalAmount,
            'transaction_id' => $request->MerchantTransactionId,
            'description'    => 'Online Bill Payment: ' . $gateway
        );

        (new PaymentController)->billGenerateIfNotExist($request->ValueA);
        $client = Client::with('clientsinfo', 'pop', 'pop.reseller', 'customerAccount', 'generatedBill')->withCount('generatedBill')->find($info['customer_id']);

        $payment = Billpayment::create([
            'description'           =>  $info['description'],
            'paid_amount'           =>  $info['amount'] ?? 0,
            'discount_amount'       =>  0,
            'client_id'             =>  $info['customer_id'],
            'user_id'               =>  User::onlinePaymentUser($gateway)->id,
            'created_at'            =>  now(),
            'collected_by'          =>  Employee::onlinePaymentEmployee($gateway)->id,
            'money_receipt_number'  =>  'SSL_' . $info['transaction_id'],
            'trx_id'                =>  $info['transaction_id'],
            'payment_method'        =>  'Online Payment',
            'client_id_time'        =>  $info['customer_id'] . '_' . now()->format('Y-m-d H:i')
        ]);

        $income =   Income::create([
            'name' => 'Online Payment by ' . $gateway,
            'date' => now(),
            'amount' => $info['amount'] ?? 0,
            'description' => 'Online Bill Payment (' . $gateway . ')  for customer : ' . $client->userid,
            'incomeHead' => 11
        ]);
        $payment->income_id = $income->id;
        $payment->save();

        CustomerAccount::updateCustomrAccount($info['customer_id'], (-$info['amount']), $info['amount'], 0);
        $cac = CustomerAccount::where('client_id', $client->id)->first();
        $current_due_amount = $client->customerAccount->dueAmount ?? 0;
        $status = (new PaymentController)->performeExpireDateExtend($client, $payment, $cac, $info['amount'], $client->pop, $current_due_amount, 'billpay', 0);

        if (checkAPI()) {
            ClientSyncJobForSingle::dispatch($client->id);
        }

        if ($status == 'balance_error') {
            return 'error';
        } else {
            if (checkSettings('auto-payment-sms-send') == 'enable') {
                try {
                    $present_due = $current_due_amount - $info['amount'];
                    (new PaymentSms)->billPaymentSms($client, $info['amount'], $info['transaction_id'], $payment->id, 'epsPayment', null, $present_due);
                } catch (\Exception $e) {
                }
            }

            // check if payment email will be send
            $emailSetting = json_decode(emailSetting()->where('tamplate_name', 'customer_payment_eamil')->first()->email_body);
            if ($emailSetting->sendemail == 'Yes') {
                try {
                    SendPaymentMailJob::dispatch($client, $payment, $emailSetting);
                } catch (\Exception $e) {
                }
            }

            // $info = array(
            //     'id' => $request->ValueA,
            //     'login_status' => 'success'
            // );

            // $request->session()->put('customer_info', json_encode($info));
            return 'success';
        }
    }

    public function failed(Request $request)
    {
        $tran_id = $request->input('MerchantTransactionId');
        $post_data = json_encode($request->all());

        $update_order_page = DB::table('orders')
            ->where('transaction_id', $tran_id)
            ->update(['post_data' => $post_data]);

        if (isset($request['val_id']) && $request['val_id'] != null) {
            DB::table('orders')
                ->where('transaction_id', $request->input('MerchantTransactionId'))
                ->update(['val_id' => $request['val_id']]);
        }

        $order_detials = DB::table('orders')
            ->where('transaction_id', $tran_id)
            ->select('transaction_id', 'status', 'currency', 'amount')->first();

        if ($order_detials->status == 'Pending') {
            $update_product = DB::table('orders')
                ->where('transaction_id', $tran_id)
                ->update(['status' => 'Failed']);

            Toastr::error('Payment Falied', 'Falied');
            return redirect()->route('customerDashboard')->with('error_message', 'Transaction is Falied');
        } else if ($order_detials->status == 'Processing' || $order_detials->status == 'Complete') {
            Toastr::error('Transaction is already Successful', 'Falied');
            return redirect()->route('customerDashboard')->with('success_message', 'Transaction is already Successful');
        } else {
            Toastr::error('Transaction is Invalid', 'Falied');
            return redirect()->route('customerDashboard')->with('error_message', 'Transaction is Invalid');
        }
    }

    public function cancel(Request $request)
    {
        $tran_id = $request->input('MerchantTransactionId');
        $post_data = json_encode($request->all());

        $update_order_page = DB::table('orders')
            ->where('transaction_id', $tran_id)
            ->update(['post_data' => $post_data]);

        if (isset($request['val_id']) && $request['val_id'] != null) {
            DB::table('orders')
                ->where('transaction_id', $request->input('MerchantTransactionId'))
                ->update(['val_id' => $request['val_id']]);
        }

        $order_detials = DB::table('orders')
            ->where('transaction_id', $tran_id)
            ->select('transaction_id', 'status', 'currency', 'amount')->first();

        if ($order_detials->status == 'Pending') {
            $update_product = DB::table('orders')
                ->where('transaction_id', $tran_id)
                ->update(['status' => 'Canceled']);
            return redirect()->route('customerDashboard')->with('error_message', 'Transaction is Canceled');
            echo "Transaction is Cancel";
        } else if ($order_detials->status == 'Processing' || $order_detials->status == 'Complete') {
            return redirect()->route('customerDashboard')->with('success_message', 'Transaction is already Successful');
            echo "Transaction is already Successful";
        } else {
            return redirect()->route('customerDashboard')->with('success_message', 'Transaction is Invalid');
            echo "Transaction is Invalid";
        }
    }

    public function ipn(Request $request)
    {
        $info = (array) $request->all();
        $invoice_id = $info['MerchantTransactionId'];
        // Storage::put('file.txt', $request->all());
        // dd($request->input('tran_id'));
        #Received all the payement information from the gateway
        if ($request->input('MerchantTransactionId')) #Check transation id is posted or not.
        {
            try {
                $new_post_data = json_encode($request->all());
                DB::table('orders')
                    ->where('transaction_id', $request->input('MerchantTransactionId'))
                    ->update(['ipn_data' => $new_post_data, 'software_integration_comment' => "from ipn"]);

                if (isset($request['val_id']) && $request['val_id'] != null) {
                    DB::table('orders')
                        ->where('transaction_id', $request->input('MerchantTransactionId'))
                        ->update(['val_id' => $request['val_id']]);
                }
            } catch (\Exception $e) {
            }
            $tran_id = $request->input('MerchantTransactionId');
            #Check order status in order tabel against the transaction id or order id.
            $order_details = DB::table('orders')
                ->where('transaction_id', $tran_id)
                ->select('transaction_id', 'status', 'currency', 'amount')->first();

            if ($order_details->status == 'Pending') {
                $payment_status = $this->CheckPaymentStatus($invoice_id);

                if ($payment_status->Status == 'Success') {
                    /*
                    That means IPN worked. Here you need to update order status
                    in order table as Processing or Complete.
                    Here you can also sent sms or email for successful transaction to customer
                    */
                    $update_product = DB::table('orders')
                        ->where('transaction_id', $tran_id)
                        ->update(['status' => 'Processing']);

                    echo "Transaction is successfully Completed";
                } else {
                    /*
                    That means IPN worked, but Transation validation failed.
                    Here you need to update order status as Failed in order table.
                    */
                    $update_product = DB::table('orders')
                        ->where('transaction_id', $tran_id)
                        ->update(['status' => 'Failed']);

                    echo "validation Fail";
                }
            } else if ($order_details->status == 'Processing' || $order_details->status == 'Complete') {
                #That means Order status already updated. No need to udate database.
                echo "Transaction is already successfully Completed";
            } else {
                #That means something wrong happened. You can redirect customer to your product page.
                echo "Invalid Transaction";
            }
        } else {
            echo "Invalid Data";
        }
    }
}
