<?php
/**
 * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
 *
 * @author Double Bastion LLC
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

declare(strict_types=1);

namespace OCA\SMSRelentless\Controller;

use OCP\IRequest;
use OCP\AppFramework\Controller;
use OCA\SMSRelentless\Service\SmsrelentlessService;
use OCP\AppFramework\App;
use OC\Http\Client\Client;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IL10N;
use OCP\Files\Folder;
use OCP\IConfig;
use OC\Files\Filesystem;
use OC\Files\View;
use \ReflectionClass;
use \FilesystemIterator;
use \DateTime;
use OCP\AppFramework\Http\DataResponse;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use Plivo\RestClient;
use Twilio\Rest\TwilioClient;


class SmsrelentlessController extends Controller {

    private $service;
    private $config;
    private $userId;
    private $folder;
    private $filesystem;
    private $view;

    public function __construct($appName, IRequest $request, SmsrelentlessService $service, IConfig $config, $userId, Folder $folder, Filesystem $filesystem, View $view) {
        parent::__construct($appName, $request);
        $this->service = $service;
        $this->config = $config;
        $this->userId = $userId;
        $this->folder = $folder;
        $this->filesystem = $filesystem;
        $this->view = $view;
    }


    /**
     * @NoAdminRequired
     */
    public function object_to_array($obj) {
        if(is_object($obj)) $obj = (array)$this->dismount($obj);
        if(is_array($obj)) {
           $new = array();
           foreach($obj as $key => $val) {
               $new[$key] = $this->object_to_array($val);
           }
        }
        else $new = $obj;
        return $new;
    }


    /**
     * @NoAdminRequired
     */
    public function dismount($object) {
        $reflectionClass = new ReflectionClass(get_class($object));
        $array = array();
        foreach ($reflectionClass->getProperties() as $property) {
           $property->setAccessible(true);
           $array[$property->getName()] = $property->getValue($object);
           $property->setAccessible(false);
        }
        return $array;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalancetel($userId) {

        $telsmsapicred = $this->service->getapicredentials($this->userId);

        $telapikey = $telsmsapicred[0];
        $ch = curl_init();
        $headerstel = array("Content-Type: application/json", "Accept: application/json", "Authorization: Bearer ".$telapikey);

        curl_setopt($ch, CURLOPT_URL, "https://api.telnyx.com/v2/balance");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headerstel);
        $responsetel = curl_exec($ch);
        $recdatatel = json_decode($responsetel, TRUE);
        $telbalresponse = $recdatatel['data']['balance'];
        $currentbalancetel = round(floatval($telbalresponse), 3);
        curl_close($ch);

        return $currentbalancetel;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalancenex($userId) {

        $smsapicred = $this->service->getapicredentials($this->userId);
        $smsapikey = $smsapicred[5];
        $smsapisecret = $smsapicred[6];

        if ($smsapikey == '' || $smsapisecret == '') {
            $currentbalancenex = "N/A";
        } else {
            $getmesdata = "https://".$smsapikey.":".$smsapisecret."@api.plivo.com/v1/Account/".$smsapikey."/";
            $mesdata = file_get_contents($getmesdata);
            $datainit = json_decode($mesdata);
            $balancenex = $datainit->cash_credits;
            $currentbalancenex = round(floatval($balancenex), 3);
        }
        return $currentbalancenex;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalancetwil($userId) {

        $smsapicred = $this->service->getapicredentials($this->userId);
        $smsapisid = $smsapicred[15];
        $smsapitoken = $smsapicred[16];

        if ($smsapisid == '' || $smsapitoken == '') {
            $currentbalancetwil = "N/A";
        } else {
            $client = new TwilioClient($smsapisid, $smsapitoken);
            $balancetwil = $client->balance->fetch()->balance;
            $currentbalancetwil = round(floatval($balancetwil), 3);
        }
        return $currentbalancetwil;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalanceflow($userId) {

        $currentbalanceflow = 'n/a';

        return $currentbalanceflow;
    }


    /**
     * @NoAdminRequired
     */
    public function getsmsnumbers($userId) {

        $smsapicred = $this->service->getapicredentials($this->userId);

        $telnyxkey = $smsapicred[0];

        $nexapikey = $smsapicred[5];
        $nexapisecret = $smsapicred[6];

        $twilapikey = $smsapicred[15];
        $twilapisecret = $smsapicred[16];

        $flowapikey = $smsapicred[20];
        $flowapisecret = $smsapicred[21];

        $telsendernameinit = $smsapicred[9];
        $nexsendernameinit = $smsapicred[10];
        $twilsendernameinit = $smsapicred[19];
        $flowsendernameinit = $smsapicred[24];

        $telsendername = "Tx: " . $telsendernameinit;
        $nexsendername = "Pl: " . $nexsendernameinit;
        $twilsendername = "Tw: " . $twilsendernameinit;
        $flowsendername = "Fl: " . $flowsendernameinit;

        // Get Telnyx phone numbers
        if ($telnyxkey != '') {

           \Telnyx\Telnyx::setApiKey($telnyxkey);
           $telnumbers = \Telnyx\MessagingPhoneNumber::All();

           $telnumbersarr = $this->object_to_array($telnumbers);
           $telnmbrs = [];

           foreach ($telnumbersarr['_originalValues'] as $nmbkey => $nmbvalue) {
              if (is_int($nmbkey)) {
                 foreach ($nmbvalue as $nkey => $nvalue) {
                    if ($nkey == 'phone_number') {
                       $telnmbrs[] = "Tx: " . $nvalue;
                    }
                 }
              }
           }

        } else { $telnmbrs = []; }

        // Get Plivo phone numbers
        if ($nexapikey != '' && $nexapisecret != '') {

           $getacdata = "https://".$nexapikey.":".$nexapisecret."@api.plivo.com/v1/Account/".$nexapikey."/Number/";
           $acdata = file_get_contents($getacdata);
           $datainit = json_decode($acdata, true);

           $findata = $this->object_to_array($datainit);

           $nexcurrentnmbrs = [];

           foreach ($findata['objects'] as $smskey => $smsvalue) {
                   if (is_array($smsvalue)) {
                         foreach ($smsvalue as $smskey2 => $smsvalue2) {
                               if ($smskey2 == 'number') {
                                   $nexcurrentnmbrs[] = "Pl: +" . $smsvalue2;
                               }
                         }
                   }
           }


        } else { $nexcurrentnmbrs = []; }

        // Get Twilio phone numbers
        if ($twilapikey != '' && $twilapisecret != '') {

            $clienttw = new TwilioClient($twilapikey, $twilapisecret);
            $accdata = $clienttw->getAccount();
            $activeNumbers = $accdata->incomingPhoneNumbers;
            $activeNumbersArr = $activeNumbers->read();
            $twilcurrentnmbrs = [];

            foreach ($activeNumbersArr as $activeNmbr) {
                     $twilcurrentnmbrs[] = "Tw: " . $activeNmbr->phoneNumber;
            }

        } else { $twilcurrentnmbrs = []; }

        // Get Flowroute phone numbers
        if ($flowapikey != '' && $flowapisecret != '') {

            $flnbrsresult = json_decode(file_get_contents("https://".$flowapikey.":".$flowapisecret."@api.flowroute.com/v2/numbers"));
            $flnbrsarr = $flnbrsresult->data;
            $flowcurrentnmbrs = [];
            foreach ($flnbrsarr as $flkey => $flitem) {
                     $flowcurrentnmbrs[] = "Fl: +" . $flitem->id;
            }

        } else { $flowcurrentnmbrs = []; }


        $telsenderarr = [0 => $telsendername];
        $nexsenderarr = [0 => $nexsendername];
        $twilsenderarr = [0 => $twilsendername];
        $flowsenderarr = [0 => $flowsendername];

        $currentnmbrs = array_merge($telnmbrs, $nexcurrentnmbrs, $twilcurrentnmbrs, $flowcurrentnmbrs, $telsenderarr, $nexsenderarr, $twilsenderarr, $flowsenderarr);

        return $currentnmbrs;
    }


    /**
     * @NoAdminRequired
     */
    public function cleantempdir($userId) {

        // Create the temporary folder if it doesn't exist
        if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
            $this->folder->newFolder('SMS_Relentless/temp_files');
        }
        $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
        $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/temp_files";
        $fileSystemIterator = new FilesystemIterator($targetdir);

        $dirfiles = [];
        foreach ($fileSystemIterator as $fileInfo){
                 $dirfiles[] = $fileInfo->getFilename();
        }

        foreach ($dirfiles as $key => $indfile) {
                 $thisuserroot = $this->view->getRoot();
                 $tempfile = $thisuserroot . "/SMS_Relentless/temp_files/" . $indfile;
                 $removetmpfile = $this->filesystem->unlink($tempfile);
        }
     }


    /**
     * @NoAdminRequired
     */
    public function uploadNumbersFile($userId, $uploadfileforsms) {

        // Create the temporary folder if it doesn't exist
        if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
            $this->folder->newFolder('SMS_Relentless/temp_files');
        }

        // First delete any file that has been previously uploaded
        $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
        $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/temp_files";
        $fileSystemIterator = new FilesystemIterator($targetdir);

        $dirfiles = [];
        foreach ($fileSystemIterator as $fileInfo){
                 $dirfiles[] = $fileInfo->getFilename();
        }

        foreach ($dirfiles as $key => $indfile) {
                 $thisuserroot = $this->view->getRoot();
                 $tempfile = $thisuserroot . "/SMS_Relentless/temp_files/" . $indfile;
                 $removetmpfile = $this->filesystem->unlink($tempfile);
        }

        // Upload the new file
        $fileContent = file_get_contents($_FILES['uploadfileforsms']['tmp_name']);
        $fileName = $_FILES['uploadfileforsms']['name'];

        $userroot = $this->view->getRoot();
        $targetfile = $userroot . "/SMS_Relentless/temp_files/" . $fileName;

        $target = $this->folder->newFile($targetfile);
        $target->putContent($fileContent);

        // Extract the phone numbers from the file
        $numberarraysec = str_replace(array(";", "|", "\r\n", "\r", "\n", "\t"), ",", $fileContent);
        $numberarraytert = preg_replace("/[^0-9,]/", "", $numberarraysec);
        $numberarrayfourth = explode(",", $numberarraytert);
        $numberarrayfifth = array_filter(array_map('trim', $numberarrayfourth));
        $numberarray = array_unique($numberarrayfifth);

        return $numberarray;
    }


    /**
     * @NoAdminRequired
     */
//    public function sendsmstel($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $encoding, $sentsmstext) {
    public function sendsmstel($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext) {

         $telsmsapicred = $this->service->getapicredentials($this->userId);
         $telnyxkey = $telsmsapicred[0];
         $teldelrecurl = $telsmsapicred[3];
         $messagingprofid = $telsmsapicred[4];

         \Telnyx\Telnyx::setApiKey($telnyxkey);

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keytel => $tonumber) {

             usleep($microinterval);

             if (preg_match('/[A-Za-z]+/', $fromsender)) {
                 $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "messaging_profile_id" => $messagingprofid]);
             } else {
                 $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl]);
             }

             $messageid = $message['id'];
             $messagedate = date("Y-m-d H:i:s");
             $messagefrom = "Telnyx: " . $fromsender;
             $messageto = $tonumber;
             $messagenetwork = null;
             $messageprice = null;
             $messagestatus = $message['to'][0]['status'];
             $messagedelivery = null;
             $messagetext = $sentsmstext;

             $sentmessagearr = [$messageid, $messagedate, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetext];

             $this->service->insertsentsms($this->userId, $sentmessagearr);

         }
    }


    /**
     * @NoAdminRequired
     */
    public function sendsmsnex($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext) {

         $smsapicred = $this->service->getapicredentials($this->userId);

         $smsapikey = $smsapicred[5];
         $smsapisecret = $smsapicred[6];
         $smsapideliveryrecurl = $smsapicred[8];

         $microinterval = $waitinterval * 1000;

         $client = new RestClient($smsapikey, $smsapisecret);

         foreach ($receiversPhoneNbs as $keynex => $tonumber) {

             usleep($microinterval);

             $response = $client->messages->create($fromsender,[$tonumber],$sentsmstext,["url" => $smsapideliveryrecurl],);

	     $messageidinit = $response->getmessageUuid(0);
             $messageid = $messageidinit[0];

             $messagedate = date("Y-m-d H:i:s");

             if (preg_match('/[A-Za-z]+/', $fromsender)) {
                 $messagefrom = "Plivo: " . $fromsender;
             } else { $messagefrom = "Plivo: +" . $fromsender; }

             $messageto = $tonumber;
             $messagenetwork = null;
             $messageprice = null;
             $messagestatus = "The message has been accepted for delivery.";
             $messagedelivery = null;
             $messagetext = $sentsmstext;

             $sentmessagearr = [$messageid, $messagedate, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetext];

             $this->service->insertsentsms($this->userId, $sentmessagearr);
         }
    }


    /**
     * @NoAdminRequired
     */
    public function sendsmstwil($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext) {


         $smsapicred = $this->service->getapicredentials($this->userId);

         $sid = $smsapicred[15];
         $token = $smsapicred[16];
         $smsapideliveryrecurl = $smsapicred[18];

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keytwil => $tonumbertw) {

             usleep($microinterval);

	     $client = new TwilioClient($sid, $token);

	     $message = $client->messages->create($tonumbertw, ['from' => $fromsender, 'body' => $sentsmstext, 'statusCallback' => $smsapideliveryrecurl]);

             $messagedate = date("Y-m-d H:i:s");

             if (preg_match('/[A-Za-z]+/', $fromsender)) {
                 $messagefrom = "Twilio: " . $fromsender;
             } else { $messagefrom = "Twilio: " . $fromsender; }

             $messageid = $message->sid;
             $messageto = $tonumbertw;
             $messagenetwork = '';
             $messageprice = '';
             $messagestatus = $message->status;
             $messagedelivery = '';
             $messagetext = $sentsmstext;

             $sentmessagearr = [$messageid, $messagedate, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetext];

             $this->service->insertsentsms($this->userId, $sentmessagearr);
         }

    }


    /**
     * @NoAdminRequired
     */
    public function sendsmsflow($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext) {

         $smsapicredfl = $this->service->getapicredentials($this->userId);

         $flowapikey = $smsapicredfl[20];
         $flowapisecret = $smsapicredfl[21];
         $flowdelrecurl = $smsapicredfl[23];
         $sentsmstextproc = str_replace('"','\\"', $sentsmstext);

         $microinterval = $waitinterval * 1000;

         foreach ($receiversPhoneNbs as $keyflow => $tonumberfl) {

             usleep($microinterval);

	     $chfl = curl_init();
	     curl_setopt($chfl, CURLOPT_URL, 'https://'.$flowapikey.':'.$flowapisecret.'@api.flowroute.com/v2.1/messages');
	     curl_setopt($chfl, CURLOPT_HTTPHEADER, array("Content-Type: application/vnd.api+json"));
	     curl_setopt($chfl, CURLOPT_TIMEOUT, 300);
	     curl_setopt($chfl, CURLOPT_RETURNTRANSFER, 1);
	     curl_setopt($chfl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
	     curl_setopt($chfl, CURLOPT_POST, 1);
	     curl_setopt($chfl, CURLOPT_POSTFIELDS, '{"to": "'. $tonumberfl .'", "from": "'. $fromsender .'", "body": "'. $sentsmstextproc .'", "dlr_callback": "'. $flowdelrecurl .'"}');
	     $resultfl = curl_exec ($chfl);
	     $statusCode = curl_getinfo($chfl, CURLINFO_HTTP_CODE);
	     curl_close ($chfl);

             $decresultfl = json_decode($resultfl);
             $messageidfl = $decresultfl->data->id;

	     if ($statusCode == 202) { $messagestatusfl = 'The message has been accepted for delivery.'; } else { $messagestatusfl = 'An error occurred while trying to send the message.'; }

             $messagedatefl = date("Y-m-d H:i:s");

             if (preg_match('/[A-Za-z]+/', $fromsender)) {
                 $messagefromfl = "Flowroute: " . $fromsender;
             } else { $messagefromfl = "Flowroute: " . $fromsender; }

             $messagetofl = $tonumberfl;
             $messagenetworkfl = '';
             $messagepricefl = '';
             $messagedeliveryfl = '';
             $messagetextfl = $sentsmstext;

             $sentmessagearr = [$messageidfl, $messagedatefl, $messagefromfl, $messagetofl, $messagenetworkfl, $messagepricefl, $messagestatusfl, $messagedeliveryfl, $messagetextfl];

             $this->service->insertsentsms($this->userId, $sentmessagearr);
         }

    }


    /**
     * @NoAdminRequired
     */
    public function saveoldrecrows($userId, $oldrecRows) {

           // Create the folder for removed messages if it doesn't exist
           if ($this->folder->nodeExists('SMS_Relentless/removed_received_messages') == false) {
               $this->folder->newFolder('SMS_Relentless/removed_received_messages');
           }
           $savecheck = 0;

           if (count($oldrecRows) > 1) {
               $msfileContent = implode("", $oldrecRows);

               $delrowsdate = date("Y-m-d_H-i-s");
               $msfileName = "Received_Messages_Deleted_On_" . $delrowsdate . ".csv";

               $userroot = $this->view->getRoot();
               $targetfile = $userroot . "/SMS_Relentless/removed_received_messages/" . $msfileName;

               $target = $this->folder->newFile($targetfile);
               $target->putContent($msfileContent);

               if ($this->filesystem->file_get_contents($targetfile) != '') {
                   $savecheck = 1;
               }
           }

           return $savecheck;
    }


    /**
     * @NoAdminRequired
     */
    public function saveoldsentrows($userId, $oldsentRows) {

           // Create the folder for removed messages if it doesn't exist
           if ($this->folder->nodeExists('SMS_Relentless/removed_sent_messages') == false) {
               $this->folder->newFolder('SMS_Relentless/removed_sent_messages');
           }
           $savesentcheck = 0;

           if (count($oldsentRows) > 1) {
               $sntfileContent = implode("", $oldsentRows);

               $delsentrowsdate = date("Y-m-d_H-i-s");
               $sntfileName = "Sent_Messages_Deleted_On_" . $delsentrowsdate . ".csv";

               $userroot = $this->view->getRoot();
               $snttargetfile = $userroot . "/SMS_Relentless/removed_sent_messages/" . $sntfileName;

               $snttarget = $this->folder->newFile($snttargetfile);
               $snttarget->putContent($sntfileContent);

               if ($this->filesystem->file_get_contents($snttargetfile) != '') {
                   $savesentcheck = 1;
               }
           }

           return $savesentcheck;
    }


    /**
     * @NoAdminRequired
     */
    public function getreceivedtable($userId) {
           return $this->service->getreceivedtable($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function getreceivedtablefordel($userId) {
           return $this->service->getreceivedtablefordel($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function removerecrows($userId, $recmessagedbIDs) {
           return $this->service->removerecrows($this->userId, $recmessagedbIDs);
    }

    /**
     * @NoAdminRequired
     */
    public function getsenttable($userId) {
           return $this->service->getsenttable($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function getsenttablefordel($userId) {
           return $this->service->getsenttablefordel($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function removesentrows($userId, $sentmessagedbIDs) {
           return $this->service->removesentrows($this->userId, $sentmessagedbIDs);
    }

    /**
     * @NoAdminRequired
     */
    public function getmessagesperpage($userId) {
           return $this->service->getmessagesperpage($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function getdelrecsettings($userId) {
           return $this->service->getdelrecsettings($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function getsettings($userId) {
           return $this->service->getsettings($this->userId);
    }

    /**
     * @NoAdminRequired
     */
    public function updatesettings($userId, $telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, $flowapiUrlRec, $flowapiUrl, $flowSenderName) {
           return $this->service->updatesettings($this->userId, $telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, $flowapiUrlRec, $flowapiUrl, $flowSenderName);
    }

}
