<?php

namespace App\Http\Controllers\Admin;

use App\Campaigns;
use App\CampaignsJobProvider;
use App\CampaignTracking;
use App\FCMNotification;
use App\Http\Controllers\Controller;
use App\Imports\CampaignImport;
use App\JobProvider;
use App\OCRRecognition;
use App\Templates;
use App\Shortio;
use App\User;
use Carbon\Carbon;
use Hashids\Hashids;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Maatwebsite\Excel\Facades\Excel;

class CampaignController extends Controller
{
    private $request;
    private $from_date;
    private $to_date;

    public function __construct(Request $request){
        $this->request = $request;
        $this->from_date = ($this->request->has('from_date')) ? Carbon::createFromFormat('Y-m-d',$this->request->get('from_date'))->startOfDay()->toDateTimeString() : Carbon::now()->startOfDay()->toDateTimeString();
        $this->to_date = ($this->request->has('to_date')) ? Carbon::createFromFormat('Y-m-d',$this->request->get('to_date'))->endOfDay()->toDateTimeString() : Carbon::now()->endOfDay()->toDateTimeString();
    }

    public function getCampaign(){
        $data['from_date'] = $this->from_date;
        $data['to_date'] = $this->to_date;

        return view('admin.reports.campaign', $data);
    }

    public function runCampaign(){
        if ($this->request->has('campaign_file')) {
        
            if($this->request->files->get('campaign_file') != null) {
                if(filesize($this->request->files->get('campaign_file')) > 18874368){
                Session::flash('error', 'Uploaded file is too large');
                return redirect()->back();
                }
            }
            
        }
        $data['from_date'] = $this->from_date;
        $data['to_date'] = $this->to_date;

        if($this->request->hasFile('campaign_file')){
            $data['variables'] = $this->importCampaignFile();
        }
        $data['campaigns'] = Campaigns::with('user')->where('created_at', '>=', $this->from_date)->where('created_at','<=',$this->to_date)->get();

        foreach ($data['campaigns'] as $campaign){
            if (strtotime($campaign->schedule) > time()) {
                $data['running_campaigns'][] = $campaign;
            }
        }

        return view('admin.reports.run-campaign', $data);
    }

    public function importCampaignFile(){
        Excel::import(new CampaignImport(new Request(['from' => __FUNCTION__])), request()->file('campaign_file'));
        $details = Session::get('CAM_Details');
        Session::forget('CAM_Details');
        $s3 = Storage::disk('s3');
        $file = $this->request->file('campaign_file');
        $excelDataPath = '/campaign/'.time().'_'.$file->getClientOriginalName();
        $uploadedExcelDataPath = $s3->put($excelDataPath, $file);
        $details = json_decode($details, 1);
        $details['campaign_file_path'] = $uploadedExcelDataPath;
        return $details;
    }

    public function runQuery(){
        $query = $this->request->get('query');
        $queryTypes = ['update','delete','create','insert','drop','alter','show','use','describe'];

        if (!empty(array_intersect(explode(' ',strtolower($query)), $queryTypes))){
            return response()->json(['message' => "Invalid query, you can't use ".implode(', ',$queryTypes)." words in query"], 200);
        }

        try {
            $response = DB::select($query);
        }catch (\Throwable $t){
            return response()->json(['message' => 'Exception occurred while running campaign query'], 200);
        }
        $sms = 0;
        $email = 0;
        $newData = [];
        $data = [];
        $table = '<table class="table table-striped">';
        $tableHead = '<thead>';
        $tableData = '';
        $keys = [];
        $sampleData = [];
        foreach ($response as $index=>$item){
            if ((isset($item->mobile_number) && !empty($item->mobile_number)) || isset($item->contact_number) && !empty($item->contact_number))
                $sms ++;
            if (isset($item->email) && !empty($item->email))
                $email ++;

            $keys = array_keys((array)$item);

            $tableData .= '<tr>';
            foreach ($keys as $key){
                if (!$index){
                    $tableHead .= '<th>'.ucwords(str_replace('_',' ',$key)).'</th>';
                }
                $key_name = wall_decrypt($item->$key);
                $tableData .= '<td>'.$key_name.'</td>';
                $newData[$key] = $key_name;

                if (!$index){
                    $sampleData[$key] = $key_name;
                }
            }
            $tableData .= '</tr>';

            $data[] = $newData;
        }

        $itemData = array_map(function($key){
            return ['id' => 0, 'name' => $key];
        }, $keys);

        $table .= $tableHead.'</thead>';
        $table .= $tableData;
        $table .= '</table>';
        $dataItem = ['total' => count($response), 'sms' => $sms, 'email' => $email, 'table' => $table, 'keys' => $itemData, 'sample_data' => $sampleData];
        if ($this->request->has('internal')){
            $dataItem['data'] = $data;
        }
        return response()->json(['data' => $dataItem], 200);
    }

    public function uploadAttachment($id){
        $files = [];
        $s3 = Storage::disk('s3');
        foreach ($this->request->allFiles() as $file) {
            $file_path = '/campaign/'.$id.'/'.time().'_'.$file->getClientOriginalName();
            $path = $s3->put($file_path, $file);
            $files[] = $path;
        }

        return implode('@@', $files);
    }

    public function saveCampaign(){
        request()->merge((array)json_decode($this->request->get('data'), 1));

        if($this->request->has('query') && $this->request->has('message') && $this->request->has('campaign_name') && $this->request->has('sms') && $this->request->has('email') && $this->request->has('whatsapp') && $this->request->has('schedule')){

            if ($this->request->get('is_test') == 0) {

                $schedule = $this->request->has('schedule') && !empty($this->request->get('schedule')) ? $this->request->get('schedule') : Carbon::now()->toDateTimeString();
                $campaign = new Campaigns();
                $campaign->fill($this->request->input());
                $campaign->campaigned_by = $this->request->get('user_id');
                $campaign->schedule = $schedule;
                $campaign->is_schedule = $this->request->has('schedule') && !empty($this->request->get('schedule')) ? 1 : 0;
                $campaign->save();

                if($this->request->has('campaign_file_path')) {
                    $campaign->attachments = $this->uploadAttachment($campaign->id);
                    $campaign->excelData = $this->request->get('campaign_file_path');
                    $campaign->save();
                }

                $this->setupJob($campaign->id, $schedule);

                return response()->json(['status' => 'OK', 'message' => 'Successfully added the campaign in queue'], 200);
            }

            if ($campaignResult = $this->sendTestCampaign()){
                return $campaignResult;
            }

        }else{
            return response()->json(['status' => 'FAIL', 'message' => 'There is an issue with this campaign'], 200);
        }
    }

    public function getTrackingURL($body, $type, $campaign, $item){

        if(isset($campaign->tracking_url) && $campaign->tracking_url && isset($campaign->id)) {

            $encoded_string = json_encode($item);
            $encoded_string = wall_encrypt($encoded_string);
            $encoded_string = str_replace('+','@14@',$encoded_string);
            $hashids = new Hashids('Creditfair by CS', 20);
            $hashed_id = $hashids->encode($campaign->id);

            $source_type = 5;

            switch ($type){
                case 'MAIL':
                    $source_type = 1;
                    break;
                case 'WHATSAPP':
                    $source_type = 2;
                    break;
                case 'SMS':
                    $source_type = 3;
                    break;
                case 'FCM':
                    $source_type = 4;
                    break;
            }

            $end_point = !env('APP_CONNECTION') ? 'https://test2.creditfair.in/' : 'https://creditfair.in/';

            if (isset($campaign->tracking_url) && $campaign->tracking_url && $type == 'MAIL') {
                $imageURL = $end_point.'campaign/track/'.$hashed_id.'?enc_str='.$encoded_string."&source=".$source_type;
                $link = '<img src="'.$imageURL.'"/>';
                return $body . $link;
            }

            $link = $end_point. 'campaign/track/'.$hashed_id.'?redirect=' . $campaign->tracking_url . 'LEGACYenc_str='.$encoded_string."LEGACYsource=".$source_type;
            try {
                $link = Shortio::getUrl($link);
            } catch (\Exception $e) {

            }

            return $body . '<br/>' . $link;
        }
        return $body;
    }

    public function getCampaignTrack(){
        if($this->request->has('id') && $this->request->get('id')){
            $campaign = CampaignTracking::where('campaign_id',$this->request->get('id'))->orderBy('created_at','desc')->get();
            return response()->json(['status' => 'OK', 'data' => $campaign, 'hasData' => count($campaign) ? 1 : 0]);
        }
        return response()->json(['status' => 'FAIL', 'message' => 'Please specify campaign id']);
    }

    public function sendTestCampaign(){
        $campaign = new \stdClass();
        $campaign->campaign_name = $this->request->get('campaign_name');
        $campaign->message = $this->request->get('message');
        $campaign->whatsapp = $this->request->get('whatsapp');
        $campaign->non_english = $this->request->get('non_english');
        $campaign->fcm_notification = $this->request->get('fcm_notification');
        $campaign->from_email = $this->request->get('from_email');
        $campaign->template_id = $this->request->get('template_id');

        $user = User::find($this->request->get('user_id'));

        if($this->request->has('campaign_file_path') && $this->request->get('campaign_file_path')){
            $path = $this->request->get('campaign_file_path');
            Excel::import(new CampaignImport(new Request(['from' => 'importCampaignFile'])), $path, 's3');
            $dataQueryOutput = Session::get('CAM_Details');
            Session::forget('CAM_Details');
            $dataQueryOutput = json_decode($dataQueryOutput);
        }else {
            $dataQueryOutput = $this->runQuery()->getData()->data;
        }

        $data = $dataQueryOutput->sample_data;
        $data->email = $user->email;
        $data->mobile_number = $user->mobile_number;

        if ($this->request->get('email') && $user->email){
            $this->sendCampaignMail($data, $campaign);
        }

        if($campaign->fcm_notification){
            $this->sendFCMNotifications($data, $campaign);
        }

        if ($user->mobile_number) {
            if ($this->request->get('sms')) {
                $this->sendCampaignSMS($data, $campaign);
            }
            if (!$this->request->get('sms') && $this->request->get('whatsapp')) {
                $this->sendCampaignWhatsApp($data, $campaign);
            }
        }

        return response()->json(['status' => 'OK', 'message' => 'Test campaign sent'], 200);
    }

    public function setupJob($campaign_id, $schedule){
        $payload[] = [
            'payload' => json_encode(['id' => $campaign_id]),
            'from' => 'campaign_service',
            'application_id' => $campaign_id,
            'available_at' => Carbon::parse($schedule)->toDateTimeString(),
            'created_at' => Carbon::now()->toDateTimeString()
        ];

        CampaignsJobProvider::insert($payload);
    }

    public function simplyMessageString($campaign_message, $item, $type, $campaign){
        $segments = explode(' ', $campaign_message);
        foreach ($segments as $index => $segment){
            if (strpos($segment, '@0-') !== false){
                $variable = str_replace('@0-','',$segment);
                $segments[$index] = $item->$variable;
            }
        }
        return $this->getTrackingURL(implode(' ',$segments), $type, $campaign, $item);
    }

    public function startCampaignService($payload){
        if (isset($payload->id)){
            $campaign = Campaigns::find($payload->id);
            if(isset($campaign->excelData) && $campaign->excelData){
                Excel::import(new CampaignImport(new Request(['from' => 'importCampaignFile', 'fetchData' => true])), $campaign->excelData, 's3');
                $dataQueryOutput = Session::get('CAM_Details');
                Session::forget('CAM_Details');
                $output = json_decode($dataQueryOutput);
            }else{
                $this->request = new Request(['query' => $campaign->query,'internal' => true]);
                $output = $this->runQuery()->getData()->data;
            }

            if (isset($output->data)) {


                foreach ($output->data as $item) {
                    if ($campaign->email && $item->email) {
                        $customerEmail[] = $item;
                    }
                    if (($campaign->sms || $campaign->whatsapp) && ((isset($item->mobile_number) && $item->mobile_number) || (isset($item->contact_number) && $item->contact_number))) {
                        $customerSMS[] = $item;
                    }

                    if($campaign->fcm_notification){
                        $this->sendFCMNotifications($item, $campaign);
                    }
                }

                if (isset($customerEmail)){
                    foreach ($customerEmail as $emailData){
                        $this->sendCampaignMail($emailData, $campaign);
                    }
                }

                if (isset($customerSMS)){
                    foreach ($customerSMS as $smsData){
                        if ($campaign->sms) {
                            $this->sendCampaignSMS($smsData, $campaign);
                        }
                        if (!$campaign->sms && $campaign->whatsapp) {
                            $this->sendCampaignWhatsApp($smsData, $campaign);
                        }
                    }
                }
            }
        }
    }

    public function sendFCMNotifications($data, $campaign){

        $mobile_number = isset($data->mobile_number) ? $data->mobile_number : (isset($data->contact_number) ? $data->contact_number : '');
        $email = $data->email;

        $user = User::whereHas('tokens')->where('mobile_number', $mobile_number)->first(['id', 'tokens', 'merchant_id']);

        if(!isset($user->id)){
            $user = User::whereHas('tokens')->where('email', $email)->first(['id', 'tokens', 'merchant_id']);
        }

        if(isset($user->id) && isset($user->tokens)) {

            $type = ($user->merchant_id) ? 'merchant' : 'user';
            $_id = ($user->merchant_id) ? $user->merchant_id : $user->id;


            $message = $this->simplyMessageString($campaign->message, $data, 'FCM', $campaign);


            $image = $this->getNotificationImage($campaign);

            $request = [
                'type' => $type,
                'id' => $_id,
                'application_id' => '',
                'notification_type' => 'campaign',
                'title' => $campaign->campaign_name,
                'body' => $message,
                'deeplink' => '',
                'image' => $image,
                'customer-app' => $type == 'user' ? true : false
            ];
            new FCMNotification(new Request($request));
        }
    }

    public function getNotificationImage($campaign){
        $imageURL = '';
        if($this->request->allFiles()) {
            foreach ($this->request->allFiles() as $file) {
                $filePath = time().'_'. rand(999999, 9999999) . '_' . $file->getClientOriginalName();
                $s3 = Storage::disk('s3');
                $s3->put($filePath, $file);
                $s3->setVisibility($filePath, OCRRecognition::PUBLIC);
                $imageURL = $s3->url($filePath);
                //$storage_path = Storage::disk('www')->put($filePath, $file);
                //$imageURL = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . '/content/media/' . $storage_path;
                break;
            }
        }else if ($campaign->attachments) {
            $files = explode('@@', $campaign->attachments);
            $s3 = Storage::disk('s3');
            foreach ($files as $file) {
                $s3->setVisibility($file, OCRRecognition::PUBLIC);
                $imageURL = $s3->url($file);
                break;
            }
        }

        return $imageURL;
    }

    public function sendCampaignMail($data, $campaign){

        $message = $this->simplyMessageString($campaign->message, $data, 'MAIL', $campaign);

        $emails = explode(',',$data->email);
        if ($emails) {
            \Mail::send('emails.reminders.basic_reminder',
                ['body' => $message, 'email_footer' => $campaign->from_email]
                , function ($message) use ($emails, $campaign) {
                    $message->from($campaign->from_email, 'Credit Fair');
                    $message->to($emails)->subject($campaign->campaign_name);
                    if($this->request->allFiles()) {
                        foreach ($this->request->allFiles() as $file) {
                            $message->attach($file->getRealPath(), array(
                                    'as' => $file->getClientOriginalName(),
                                    'mime' => $file->getMimeType())
                            );
                        }
                    }else if(isset($campaign->attachments) && $campaign->attachments){
                        $files = explode('@@',$campaign->attachments);
                        $s3 = Storage::disk('s3');
                        foreach ($files as $file){
                            $explodedFile = explode('/', $file);
                            $message->attachData($s3->get($file), $explodedFile[count($explodedFile) - 1]);
                        }
                    }
                });

            sleep(1);
        }
    }

    public function sendCampaignSMS($data, $campaign){
        $message = $this->simplyMessageString($campaign->message, $data, 'SMS', $campaign);
        $smsData = ['message' => $message];
        if (!$campaign->whatsapp){
            $smsData = array_merge($smsData, ['whatsapp_not' => true]);
        }
        if ($campaign->non_english){
            $smsData = array_merge($smsData, ['_preferred' => 1]);
        }
        if ($campaign->template_id){
            $smsData = array_merge($smsData, ['templateDetails' => ['templateid' => $campaign->template_id, 'entityid' => Templates::$entityid]]);
        }
        $mobile_number = isset($data->mobile_number) ? $data->mobile_number : (isset($data->contact_number) ? $data->contact_number : '');
        if ($mobile_number) {
            send_sms($mobile_number, $smsData);
        }
    }

    public function sendCampaignWhatsApp($data, $campaign){
        $message = $this->simplyMessageString($campaign->message, $data, 'WHATSAPP', $campaign);
        $mobile_number = isset($data->mobile_number) ? $data->mobile_number : (isset($data->contact_number) ? $data->contact_number : '');
        if ($mobile_number) {
            sendWhatsAppMessage($mobile_number, $message);
        }
    }
}
