<?php

namespace App\Console\Commands;

use App\Traits\Server6UssdDatabase;
use App\User;
use App\UssdPayment;
use App\UssdService;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;

class MonitorUssdPaymentSubscriptions extends Command
{

    use Server6UssdDatabase;

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'ussd:monitor';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Monitors ussd payment subscriptions for expiry and sending reminder sms';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //- monitor payment expiry for active payment subscription daily
        //- sms alert - 5 days before expiry
        //- deactivate the  service on expiry - both locally and on the server 6 database


        //holds soon to expire payments
        $soonToExpirePayments = [];

        foreach (UssdPayment::cursor() as $ussdPayment){
            //1. get the services that have 5 days for the subscription to expire
            // - find the difference between the payment date and expiry date
            // - if day difference is 5, send a reminder sms for client to renew
            if($this->willExpireInSetDays($ussdPayment)) {
                array_push($soonToExpirePayments, $ussdPayment);
            }
        }

        //holds expired payments
        $expiredPayments = [];
        foreach (UssdPayment::where('has_expired', 0)->cursor() as $ussdPayment) {
            //2. get the services that have expired
            // - find the difference between the current date and the expiry date,
            //- if the day difference is 1, deactivate the service, locally and on the server 6
            if($this->hasExpired($ussdPayment)) {
                array_push($expiredPayments, $ussdPayment);
            }
        }

        //process expired payments
        $this->processExpiredPayments($expiredPayments);

        //process soon to expire payment subscriptions
        $this->processSoonToExpirePayments($soonToExpirePayments);
    }

    /**
     * Determines if a ussd payment subscription will expire in a given number of days
     * @param UssdPayment $ussdPayment
     * @param int $days
     * @return bool
     */
    private function willExpireInSetDays(UssdPayment $ussdPayment, $days = 5)
    {
        return $ussdPayment->expiry_date->diffInDays($ussdPayment->payment_date) == $days;
    }

    /**
     * Determines if a payment subscription has expired.
     * If a service is to expire on 20th, on 21st, service should have expired.
     * @param UssdPayment $ussdPayment
     * @return bool
     */
    private function hasExpired(UssdPayment $ussdPayment)
    {
        return Carbon::now()->diffInDays($ussdPayment->expiry_date) == 1;
    }


    /**
     * Deactivate the expired ussd subscriptions
     * @param array $expiredPayments
     */
    private function processExpiredPayments(array $expiredPayments)
    {
        foreach ($expiredPayments as $expiredPayment) {
            DB::beginTransaction();
            //deactivate the service locally
            $expiredPayment->update(['has_expired' => 1]);
            //change status to deactivated
            $expiredPayment->ussd_service->update(['purchase_status' => UssdService::USSD_SERVICE_PURCHASE_STATUS_DEACTIVATED]);
            //deactivate on server 6
            //establish connection
            $connection = $this->ussdLiveDBConnection();
            //update the purchase status int the db
            $extension = $this->extractExtensionFromServiceCode($expiredPayment->ussd_service->code);
            //purchase status
            $purchaseStatus = UssdService::USSD_SERVICE_PURCHASE_STATUS_DEACTIVATED;
            mysqli_query($connection, "UPDATE services SET purchase_status = '$purchaseStatus' WHERE extension = '$extension'");

            $this->log('Service deactivated for extension code ' . $expiredPayment->ussd_service->code);
            DB::commit();
        }
    }

    /**
     * Sends mail and sms to clients to remind them of upcoming expiry of their payment subscriptions
     * @param array $soonToExpirePayments
     */
    private function processSoonToExpirePayments(array $soonToExpirePayments)
    {
        foreach ($soonToExpirePayments as $soonToExpirePayment) {
            //message to be sent
            $message = "Dear Customer, your payment subscription for our ussd service with extension " .
                $soonToExpirePayment->ussd_service->code . " will expire in 5 days time (" . $soonToExpirePayment->expiry_date . ")
            For further assistance you may contact <b>support@npontu.com</b><br>Thank you.";
            //get the user
            $user = $this->getUser($soonToExpirePayment);
            //send sms
            $this->sendSms($soonToExpirePayment, $message, $user);
            //send email
            $this->sendMail($soonToExpirePayment, $message, $user);
        }
    }


    /**
     * Send sms
     * @param UssdPayment $ussdPayment
     * @param $message
     * @param User $user
     */
    private function sendSms(UssdPayment $ussdPayment, $message, User $user)
    {
        //encode message
        $message = urlencode($message);
        //encode the number
        $number = urlencode($user->phone_number);
        //sms source
        $source = 'Deywuro Ussd';
        //sms url
        $url = "https://deywuro.com/api/sms?username=sammy&password=cse%402021_npontu&source=$source&destination=" . $number . "&message=" . $message;

        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);

        $this->log('Reminder sms sent to extension code ' . $ussdPayment->ussd_service->code);
    }


    /**
     * Send reminder email to client
     * @param UssdPayment $ussdPayment
     * @param $message
     * @param User $user
     */
    private function sendMail(UssdPayment $ussdPayment, $message, User $user)
    {
        //craft the content
        $content = ['body_ussd' => $message, 'to' => $user->email, 'name' => $user->username, 'subject' => 'USSD PAYMENT SUBSCRIPTION NOTICE','ussd'=>'ussd'];

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

        $this->log('Reminder Email sent to extension code ' . $ussdPayment->ussd_service->code);
    }


    /**
     * Retrieve user for service
     * @param UssdPayment $ussdPayment
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    private function getUser(UssdPayment $ussdPayment){
        //get the user for the service
        return User::query()->where('username', $ussdPayment->ussd_service->sms_username)->first();
    }


    /**
     * Log activities
     * @param $message
     */
    private function log($message)
    {
        $now = Carbon::parse(now());
        file_put_contents(storage_path() . '/logs/ussd-monitoring.log', "\n" . 'INFO: ' . $now . ' || ' . $message . PHP_EOL, FILE_APPEND);
    }
}
