<?php

namespace App\Http\Controllers\USSD;

use App\DataTables\USSD\USSDPaymentDatatable;
use App\ResellerUssdPayment;
use App\ResellerUssdSubscription;
use App\Traits\Server6UssdDatabase;
use App\User;
use App\UssdPayment;
use App\UssdPrice;
use App\UssdService;
use App\UssdSubscriptionBalance;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;

class UssdPaymentController extends Controller
{

    use Server6UssdDatabase;

    /**
     * Display a listing of the resource.
     *
     * @param USSDPaymentDatatable $table
     * @param UssdService $service
     * @return void
     */
    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 Response
     */
    public function edit($id)
    {
        $service = UssdService::query()->find($id);
        $prices = UssdPrice::query()->where([['is_active',true],['apply_to','clients'],['user_id'=>null]])->get();
        return view('ussd.payment.create_payment',['prices'=>$prices])->withService($service);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param Request $request
     * @param int $id
     * @return RedirectResponse|Response
     */
    public function update(Request $request, $id)
    {
        $request->validate(
            [
                'number' => 'required|digits:10',
                'voucher' => 'nullable|string',
                'channel' => 'required'
            ]
        );
        //find the service
        $service = UssdService::query()->find($id);
        $package =  UssdPrice::query()->find($request->input('price_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();

        $user_id = 'usrvfa';
        $password = 'pssvfa123';


        //generate payment request data
        $data = [
            'number' => $request['number'],
            'vendor' => $request['channel'],
            'uid'  => $user_id,
            'pass' => $password,
            'tp'   => $transactionId,
            'cbk'  => $callbackResponseUrl,
            'amt'  => $package->cost,
            'msg'  => 'Deywuro USSD subscription payment',
            'vou'  => $request['voucher'],
            'trans_type' => 'Debit'
        ];



        $this->appLog('USSD INIT '.json_encode($data));

        //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' => $package->cost,
                    'ussd_price_id' => $package->id,
                    'transaction_id' => $transactionId,
                    'status' => $result->status,
                    'payment_date' => date('Y-m-d H:i:s'),
                    'has_expired' => 0,
                    'response_message' => 'Pending'
                ]
            );

            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();

    }


    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)):
            $this->appLog('USSD PAYMENT null '.json_encode($output));
            return (object)['status' => 'failed', 'message' => 'Failed'];
        endif;

        //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
        $this->appLog('USSD PAYMENT '.json_encode($output));
        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)
    {
        try {

            $this->appLog('USSD callback resp '.json_encode($request->all()));
            //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,
                    'phone_number' => $request->input('msisdn'),
                    '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]);

                $service->update(['purchase_status'=>'paid','sessions'=>$service->ussd_payment->ussd_price->sessions]);

                $this->appLog("UPDATED SERVICE $service->code WITH SESSIONS {$service->ussd_payment->ussd_price->sessions}");


                //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;

                $SQL =  "UPDATE services SET purchase_status = '$purchaseStatus'
                and session_used = 0 and package_session = '{$service->ussd_payment->ussd_price->sessions}'
                WHERE extension = '$extension'";


                $this->appLog("QUERY SERVICE $service->code WITH QUERY {$SQL}");

                mysqli_query($connection, $SQL);

            }
        }catch (\Exception $ex)
        {
            $this->appLog('USSD callback ERROR '.$ex->getMessage());
        }
    }

    public function payCallback(Request $request)
    {
        try {

            $this->appLog("RESELLER USSD Momo" . $request->input('transaction_id') . '||' . $request->input('status'));

            $transaction_id = $request->input('transaction_id');
            $status = strtolower($request->input('status'));
            $responseMessage = $request->input('responseMessage');
            $expires_on = Carbon::parse(now())->addDays(30); //gets new expiry date
            $user_id = (integer)explode('_', $transaction_id)[0];  //converts user id to int after explosion
            $user = $this->user($user_id);  //gets the user details


            $payment = ResellerUssdPayment::query()->where('transaction_id', $transaction_id)->first();
            $payment->status   = $status;
            $payment->response = $responseMessage;
            $payment->save();  //updates the payment status

            if ($status != 'failed') {


                ResellerUssdSubscription::query()->updateOrCreate(
                    ['user_id' => $user_id],
                    [
                        'is_paid'       => true,
                        'expires_on'    => $expires_on,
                        'ussd_price_id' => $payment->ussd_price_id
                    ]
                );

                if($this->user($user_id)->role_id == 3) {   //for resellers

                    UssdSubscriptionBalance::query()->updateOrCreate(
                        ['user_id' => $user_id],
                        [
                            'ussd_price_id' => $payment->ussd_price->id,
                            'pricing'       => $payment->ussd_price->cost,
                            'sessions'      => $payment->ussd_price->sessions,
                        ]
                    );
                }


                $message = "You have successfully been subscribed to the USSD package.
                            The subscription expires on <b>$expires_on</b>.
                            For further assistance kindly contact <b>support@npontu.com</b><br>
                            Thank you.";

            }

            else {
                $message = "Your attempt to subscribe to a USSD media package failed.
                            Kindly review your request and try again
                            For further assistance you may contact <b>support@npontu.com</b><br>
                            Thank you.";
            }


            $content = ['body' => $message, 'to' => $user->email, 'name' => $user->username,'subject'=>'DEYWURO PAYMENT NOTICE'];  //gets parameters ready for sending email
            $this->sendEmail($content);
        }catch (\Exception $exception){
            $this->appLog("USSD CALLBACK EXCEPTION || " . $request->input('transaction_id') . '||' . $exception->getMessage());
        }
    }

    public function user($user)
    {
        return User::query()->find($user);
    }

    public  function sendEmail($content)
    {
        Mail::send('email_approved', $content, function ($m) use ($content) {
            $m->from('sms@deywuro.com', 'Deywuro');
            $m->to($content['to'],  $content['name']);
            $m->subject($content['subject'] ?? 'DEYWURO ALERT');
        });
    }

}
