<?php

namespace App\Http\Controllers\USSD;

use App\DataTables\USSD\USSDPaymentDatatable;
use App\Traits\Server6UssdDatabase;
use App\UssdPayment;
use App\UssdService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class UssdPaymentController extends Controller
{

    use Server6UssdDatabase;

    /**
     * Display a listing of the resource.
     *
     * @param USSDPaymentDatatable $table
     * @param UssdService $service
     * @return \Illuminate\Contracts\View\View|\Illuminate\Http\JsonResponse|\Illuminate\View\View
     */
    public function index(USSDPaymentDatatable $table, UssdService $service)
    {
        return $table->render("ussd.payment.payment_subscription", ['service' => $service]);
    }


    /**
     * Show the form for editing the specified resource.
     *
     * @param int $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $service = UssdService::query()->find($id);
        return view('ussd.payment.create_payment')->withService($service);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @param int $id
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $request->validate(
            [
                'number' => 'required|digits:10',
                'voucher_code' => 'nullable|string',
                'channel' => 'required'
            ]
        );
        //find the service
        $service = UssdService::query()->find($id);

        //payment end point
        $paymentEndpoint = "https://pay.npontu.com/api/pay";
        //callback url
        $callbackResponseUrl = route('ussd.subscription.payment.callback');
        //transaction id - begins with service id
        $transactionId = $service->id . '_' . $this->generateTransactionId();

        //generate payment request data
        $data = [
            'number' => $request['number'],
            'vendor' => $request['channel'],
            'uid' => 'npdeywuro',
            'pass' => 'hdgt2314',
            'tp' => $transactionId,
            'cbk' => $callbackResponseUrl,
            'amt' => UssdPayment::MONTHLY_AMOUNT,
            'msg' => 'Deywuro USSD subscription payment',
            'vou' => $request['voucher_code'],
            'trans_type' => 'Debit'
        ];

        //make api call for payment transaction
        $result = $this->makePayment($data, $paymentEndpoint);

        if ($result->status == 'success') {
            //save to payment table, if already exist, update
            UssdPayment::query()->updateOrCreate(['ussd_service_id' => $service->id],
                [
                    'amount' => UssdPayment::MONTHLY_AMOUNT,
                    'transaction_id' => $transactionId,
                    'status' => $result->status,
                    'payment_date' => date('Y-m-d H:i:s'),
                    'has_expired' => 0,
                    'response_message' => 'Pending approval from client'
                ]
            );

            session()->flash('success', 'Approve Transaction in your wallet to finalise payment. Thank you.');
            return redirect()->route('service.ussd.payment.subscription', $service->id);
        }

        //return error message
        session()->flash('error', 'Sorry, an error occurred in processing payment. Kindly retry.');
        return redirect()->back()->withInput();

    }


    /**
     * Make payment request with api endpoint and data
     * @param array $data
     * @param $endpoint
     * @return mixed
     */
    private function makePayment(array $data, $endpoint)
    {

        $ch = curl_init($endpoint);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $output = json_decode(curl_exec($ch));

        //if output is null because of an error, return a custom object with status failed
        if (is_null($output)) return (object)['status' => 'failed', 'message' => 'Failed'];

        //Response for mobile money is either an object or an array of object
        //If its an array, then get the first element of object and return it
        return is_object($output) ? $output : $output[0];
    }

    /**
     * Generates 12 digits long transaction id in upper case
     * @return string
     */
    public function generateTransactionId()
    {
        return strtoupper(Str::random(12));
    }

    /**
     * Callback url updates ussd subscription payment
     * @param Request $request
     */
    public function paymentCallback(Request $request)
    {
        //get the transaction id, status and response message
        $transaction_id = $request->input('transaction_id');
        $status = strtolower($request->input('status'));
        $message = $request->input('responseMessage');

        //get the service id
        $serviceId = (integer) explode('_', $transaction_id)[0];

        //find the service
        $service = UssdService::query()->find($serviceId);

        //set expiry date if not failed
        $expiryDate = $status === 'failed' ? null : Carbon::parse(now())->addDays(30);

        //update the payment record
        $service->ussd_payment()->update(
                    [
                        'status' => $status,
                        'response_message' => $message,
                        'payment_date' => date('Y-m-d H:i:s'),
                        'expiry_date' => $expiryDate,
                        'has_expired' => 0
                    ]
                );

        //update the service purchase status to paid if successful]
        if($status !== 'failed') {
            $service->update(['purchase_status' => UssdService::USSD_SERVICE_PURCHASE_STATUS_PAID]);

            //update the services table on server 6
            //establish connection
            $connection = $this->ussdLiveDBConnection();
            //insert data into the db
            $extension = $this->extractExtensionFromServiceCode($service->code);
            //purchase status
            $purchaseStatus = UssdService::USSD_SERVICE_PURCHASE_STATUS_PAID;
             mysqli_query($connection, "UPDATE services SET purchase_status = '$purchaseStatus' WHERE extension = '$extension'");
        }
    }

}
