<?php
/**
 * Created by PhpStorm.
 * User: sunilkhorwal
 * Date: 2020-10-26
 * Time: 15:40
 */
namespace App\Http\Controllers\MConnector;

use App\Http\Controllers\Admin\ConsumerApplicationController;
use App\Http\Controllers\Controller;
use App\JWTAccess;
use App\Merchant;
use App\MerchantApiCredentials;
use App\ProFormaInvoice;
use App\Slack;
use App\Webhook;
use App\WebhookRequestLogs;
use Carbon\Carbon;
use Firebase\JWT\JWT;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class MerchantApiIntegration extends Controller {

    private $request;
    private $defaultKey = '\x91P\xe7\xc7~\xc4\xf3\xaal4\xf8\xa5CCm\xcf\x1b\xd7\xff \x97\xfb\xc5\xfc';
    private $merchantSecretKey = null;

    public function __construct(Request $request){
        $this->request = $request;
    }

    public function index($id){

        $merchantApiCredentials = MerchantApiCredentials::with('user','merchant.webhook')->where('merchant_id', $id)->orderBy('created_at','desc')->get();
        $removeIpWhitelist = Merchant::where('id', $id)->pluck('remove_ip_whitelist')->first();

        $init = [
            'key' => isset($merchantApiCredentials[0]) && $merchantApiCredentials[0]->status == 1 ? $merchantApiCredentials[0]->key : '',
            'keys' => $merchantApiCredentials
        ];

        $application = new ConsumerApplicationController();
        $status = $application->status;
        $otherWebhookEvents = $application->otherWebhookEvents;

        $data = ['init' => $init, 'merchant_id' => $id, 'merchant' => isset($merchantApiCredentials[0]) ? $merchantApiCredentials[0]->merchant : '', 'status' => $status, 'otherWebhookEvents' => $otherWebhookEvents, 'removeIpWhitelist'=>$removeIpWhitelist];
        return view('admin.m-api.index', $data);
    }

    public function updateWebhook(){

        if($this->request->get('exists')){
            $webhook = Webhook::find($this->request->get('exists'));
        }else{
            $webhook = new Webhook();
        }
        $webhook->fill([
            'merchant_id' => $this->request->get('id'),
            'user_id' => $this->request->get('user_id'),
            'name' => $this->request->get('webhook_name'),
            'endpoint' => $this->request->get('webhook_url'),
            'events' => implode(',', $this->request->get('events')),
            'status' => 1,
            'created_at' => Carbon::now()->toDateTimeString()
        ]);

        $webhook->save();

        return response()->json(['status' => $webhook->id ? 'OK' :'FAIL', 'message' => $webhook->id ? 'Webhook added successfully' : 'Failed to save webhook']);
    }

    public function deleteWebhook(){
        $webhook = Webhook::where('id', $this->request->get('id'))->delete();

        return response()->json(['status' => $webhook ? 'OK' :'FAIL', 'message' => $webhook ? 'Webhook deleted successfully' : 'Failed to delete webhook']);
    }

    public function enableInit($id){

        //$merchant = Merchant::where('id', $id)->first(['id', 'slug', DB::raw('UNIX_TIMESTAMP(created_at) AS time')]);
//        $this->setDefaultPayload($merchant);
//
//        $process = new Process([_env('PYTHON3_PATH'),  __DIR__.'/jwtEE.py', $id.','.$this->merchantSecretKey]);
//        $process->run();
//
//        if (!$process->isSuccessful()) {
//            throw new ProcessFailedException($process);
//        }
//
//        $key = $process->getOutput();

        try {
            $bytes = random_bytes(16);
            $key = bin2hex($bytes);
        } catch (\Exception $e) {
            return redirect()->back()->withErrors(['Failed to communicate auth service']);
        }

        if ($key) {
            MerchantApiCredentials::insert(
                [
                    'merchant_id' => $id,
                    'key' => $key,
                    'created_at' => Carbon::now()->toDateTimeString(),
                    'created_by' => Auth::user() ? Auth::user()->id : ($this->request->has('user_id') ? $this->request->get('user_id') : 107),
                    'status' => 1
                ]
            );

            return redirect()->back();
        }

        return redirect()->back()->withErrors(['Failed to communicate auth service']);
    }

    public function changeStatus(){
        $apiKey = MerchantApiCredentials::where('id', $this->request->get('id'))->first(['id', 'status']);
        if (isset($apiKey->id)){
            $apiKey = MerchantApiCredentials::where('id', $this->request->get('id'))->update(['status' => !$apiKey->status]);
            if ($apiKey){
                return response()->json(['status' => 'OK']);
            }
        }

        return response()->json(['status' => 'FAIL', 'message' => 'Failed to change the status']);
    }

    public function updateIPs(){
        $ipUpdate = Merchant::where('id', $this->request->get('id'))->update(['ips' => $this->request->get('ips')]);
        $ipRemove = Merchant::where('id', $this->request->get('id'))->update(['remove_ip_whitelist' => ($this->request->get('remove_ip_whitelist') == 1) ? 1 : 0]);
        if ($ipUpdate){
            return response()->json(['status' => 'OK', 'message' => 'Added Successfully']);
        }

        return response()->json(['status' => 'FAIL', 'message' => 'Failed to save']);
    }

    private function setDefaultPayload($merchant){
        $this->request->merge(['data' => ['sub' => $merchant->id, 'data' =>  ['service' => 'Active']]]);
        $this->merchantSecretKey = $merchant->id.''.strtoupper(str_replace(' ', '', $merchant->slug)).''.$merchant->time;
    }

    public function push(){

        $status = 'FAIL';
        //$invoice = ProFormaInvoice::where('application_id', $this->request->get('application_id'))->first(['loan_application_no']);

        if ($this->request->get('application_id')) {

            $webhooks = Webhook::whereIn('id', json_decode($this->request->get('webhook_id')))->where('status', 1)->get();
            //(new Slack(new Request(['title' => 'mConnect Webhook - Check 4', 'fields' => ['payload' => 'a'], 'group' => Slack::$STAGE_TESTING])))->send();

            foreach ($webhooks as $webhook) {
                if (isset($webhook->id) && (in_array($this->request->get('payload')['status'], explode(',', $webhook->events)) || (isset($this->request->get('payload')['type']) && in_array($this->request->get('payload')['type'], explode(',', $webhook->events))))) {

                    $request_id = $this->guidv4();
                    //(new Slack(new Request(['title' => 'mConnect Webhook - Check 4', 'fields' => ['end' => $webhook->endpoint], 'group' => Slack::$STAGE_TESTING])))->send();

                    //$payload = json_encode(array('applicationNo' => $invoice->loan_application_no, "status" => $this->request->get('status'), 'remark' => ''));
                    $payload = json_encode($this->request->get('payload'));
                    $_payload = $this->request->get('payload');
                    $data = $_payload['data'];
                    if(empty($data)){
                        $data = new \stdClass();
                        $_payload['data'] = $data;
                        $payload = json_encode($_payload);
                    }

                    //(new Slack(new Request(['title' => 'mConnect Webhook - Check 4', 'fields' => ['payload' => $payload], 'group' => Slack::$STAGE_TESTING])))->send();
                    $curl = curl_init();
                    curl_setopt_array($curl, array(
                        CURLOPT_URL => $webhook->endpoint,
                        CURLOPT_RETURNTRANSFER => true,
                        CURLOPT_ENCODING => "",
                        CURLOPT_MAXREDIRS => 10,
                        CURLOPT_TIMEOUT => 30,
                        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
                        CURLOPT_CUSTOMREQUEST => "POST",
                        CURLOPT_POSTFIELDS => $payload,
                        CURLOPT_HTTPHEADER => array(
                            "Content-Type: application/json",
                            "Credit-Fair-Signature:".$request_id
                        ),
                    ));

                    $response = curl_exec($curl);
                    $err = curl_error($curl);
                    $info = curl_getinfo($curl);

                    $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

                    (new Slack(new Request(['title' => 'Webhook Response Response | Curl Res', 'fields' => ['Webhook Id' => $webhook->id, 'Info' => json_encode($info), 'Signature' => $request_id, 'URL' => $webhook->endpoint, 'application_id' => $this->request->get('application_id'), 'Error' => $err, 'Response' => $response, 'http_code' => $http_code ?? 1, 'payload' => $payload], 'group' => Slack::$M_CONNECT])))->send();

                    if (!$err) {
                        switch ($http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE)) {
                            case 200:  # OK
                                WebhookRequestLogs::insert([
                                    'request_id' => $request_id,
                                    'webhook_id' => $webhook->id,
                                    'request' => json_encode($payload),
                                    'response' => $response,
                                    'application_id' => $this->request->get('application_id'),
                                    'created_at' => Carbon::now()->toDateTimeString()
                                ]);
                                $status = 'success';
                                break;
                            default:
                                WebhookRequestLogs::insert([
                                    'request_id' => $request_id,
                                    'webhook_id' => $webhook->id,
                                    'request' => json_encode($payload),
                                    'response' => $response,
                                    'application_id' => $this->request->get('application_id'),
                                    'created_at' => Carbon::now()->toDateTimeString()
                                ]);
                                (new Slack(new Request(['title' => 'Webhook Response Error | Code', 'fields' => ['Webhook Id' => $webhook, 'application_id' => $this->request->get('application_id'), 'HCode' => $http_code, 'payload' => $payload, 'response' => json_encode($response)], 'group' => Slack::$M_CONNECT])))->send();
                                $status = 'Webhook Response Error | Code';
                        }
                    }else{
                        (new Slack(new Request(['title' => 'Webhook Response Error | Curl Error', 'fields' => ['Webhook Id' => $webhook, 'application_id' => $this->request->get('application_id'), 'Error' => json_encode($err), 'payload' => $payload], 'group' => Slack::$M_CONNECT])))->send();
                        $status = 'Webhook Response Error | Curl Error';
                    }

                    curl_close($curl);
                }
            }
        }

        return $status;
    }

    function guidv4($data = null) {
        // Generate 16 bytes (128 bits) of random data or use the data passed into the function.
        try {
            $data = $data ?? random_bytes(16);
        } catch (\Exception $e) {
        }
        assert(strlen($data) == 16);

        // Set version to 0100
        $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
        // Set bits 6-7 to 10
        $data[8] = chr(ord($data[8]) & 0x3f | 0x80);

        // Output the 36 character UUID.
        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
    }
}

