<?php

namespace App\Http\Controllers;

use Formatter;
use Helper;
use App\Helpers\Inspiring;
use App\Models\Device;
use App\Models\Outbox;
use App\Models\Subscriber;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
// use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class SendmsgController extends Controller
{
  private $job_id = '';
  // private $mediafile = '';
  private $mediaurl = '';

  public function index(Request $request)
  {
    if (!empty($request->role)) {
      $broadcastPhones = preg_replace('/[^-\d,]/', '', User::where('role', $request->role)->get('phone'));
    } elseif (!empty($request->status)) {
      $broadcastPhones = preg_replace(
        '/[^-\d,]/','',
        User::where('role', '<>', 'admin')->where('billing_end', '<', Carbon::now())->get('phone')
      );
    } else {
      $broadcastPhones = null;
    }
    $user = auth()->user();
    $devices = Device::where('user_id', $user->id)->where('status', 'ONLINE')->get();
    $phonebooks = $user->phonebooks;
    $subscribers = Subscriber::where('user_id', $user->id)->orderBy('sender')->groupBy('sender')->get();
    $templates = $user->templates->sortBy('name');
    $numOfButtons = empty(Helper::setting('numOfButtons')) ? 3 : Helper::setting('numOfButtons');
    $numOfLists = empty(Helper::setting('numOfLists')) ? 3 : Helper::setting('numOfLists');
    $alertMsg = __('Sending job will continue running on the background');
    $globals = [];
    $gUserIds = empty(Helper::setting('globalUserIds')) ? null : json_decode('['.Helper::setting('globalUserIds').']');
    if($gUserIds && Helper::isEx() && $user->package->global_senders) {
      foreach($gUserIds as $gUserId) {
        if ($gUserId == $user->id) continue;
        $gDevices = Device::where('user_id', $gUserId)->get();
        if (empty($gDevices)) continue;
        foreach($gDevices as $gDevice) {
          if ($gDevice->status !== 'ONLINE') continue;
          array_push($globals, ['user_id' => $gUserId, 'name' => $gDevice->name, 'sender' => $gDevice->sender]);
        }
      }
    }
    // dd($globals);
    return view('/sendmsg', compact('broadcastPhones', 'devices', 'phonebooks', 'subscribers', 'templates', 'numOfButtons', 'numOfLists', 'alertMsg', 'globals'));
  }

  public function store(Request $request)
  {
    $request->validate(['sender' => 'required', 'mediafile' => 'nullable|file|mimes:xml,jpeg,png,jpg,gif,pdf,xls,xlsx,ppt,pptx,doc,docx,csv,mp3,ogg,mp4,zip,rar,7z']); // |max:20480
    $alertMsg = '';
    $receiversCount = 0;
    $senders = $request->input('sender');
    $sendersCount = count($senders);

    if (empty($request->input('single_receiver')) && empty($request->input('phonebook'))) {
      return redirect()
        ->back()
        ->with(['danger_alert' => __('No receivers selected. Please select at least one receiver')]);
    }

    if (!empty($request->input('single_receiver'))) {
      $i = 0;
      $phones = explode(',', $request->input('single_receiver'));
      $receivers = [];
      foreach ($phones as $phone) {
        array_push($receivers, ['phone' => $phone, 'name' => __('Sir/Madam')]);
      }
      $receiversCount += count($receivers);
      foreach ($receivers as $receiver) {
        if ($i < $sendersCount) {
          $alertMsg = __('Single receiver') . ' => ' . $this->saveToDb($request, $receiver, $senders[$i]);
          $i += 1;
        } else {
          $i = 0;
          $alertMsg = __('Single receiver') . ' => ' . $this->saveToDb($request, $receiver, $senders[$i]);
          $i += 1;
        }
      }
    }
    if (!empty($request->input('phonebook'))) {
      if (str_starts_with($request->input('phonebook'), __('Subscribers') . '-')) {
        $arrInput = explode('-', $request->input('phonebook'));
        $subscriberSender = $arrInput[1];
        if ($subscriberSender === __('ALL')) {
          $subscribers = Subscriber::where('user_id', $request->input('user_id'))->where('status', 1)->get();
        } else {
          $subscribers = Subscriber::where('user_id', $request->input('user_id'))->where('sender', $subscriberSender)->where('status', 1)->get();
        }
        $receiversCount += count($subscribers);
        foreach ($subscribers as $subscriber) {
          $this->saveToDb($request, ['name' => $subscriber->name, 'phone' => $subscriber->phone], $subscriber->sender);
        }
      } else {
        $i = 0;
        $receivers = json_decode($request->input('phonebook'), true);
        $receiversCount += count($receivers);
        foreach ($receivers as $receiver) {
          if ($i < $sendersCount) {
            $alertMsg = __('Multi receivers') . ' => ' . $this->saveToDb($request, $receiver, $senders[$i]);
            $i += 1;
          } else {
            $i = 0;
            $alertMsg = __('Multi receivers') . ' => ' . $this->saveToDb($request, $receiver, $senders[$i]);
            $i += 1;
          }
        }
      }
    }
    // Sending now
    $msgdelay = empty($request->input('max')) ? 1 : $request->input('max');
    if ($receiversCount * $msgdelay < 30 && $request->input('schedule') <= Carbon::now()) {
      $this->sendNow($request->input('job_id'));
    }
    $request->session()->flash('success_alert', $alertMsg . __('Successfully add message to outbox'));
    return redirect()->route('sendmsg.index');
  }

  private function sendNow($jobId)
  {
    $outboxes = Outbox::where('job_id', $jobId)->get();
    if (empty($outboxes[0])) {
      return;
    }
    $count = count($outboxes);
    $i = 0;
    foreach ($outboxes as $outbox) {
      $i++;
      try {
        $response = self::sendMessage($outbox->receiver, $outbox->msgtext, $outbox->sender, $outbox->mediaurl, $outbox->data, $outbox->id);
        $res = json_decode($response);
        if (!empty($res->success)) {
          $outbox->status = 'SENT';
        } else {
          $outbox->status = isset($res->isonwa) && $res->isonwa === false ? 'FAILED(NOT WA)' : 'FAILED';
        }
        $outbox->save();
        if (!empty($outbox->msgdelay) && $i < $count) {
          sleep($outbox->msgdelay);
        }
      } catch (Exception $e) {
        $outbox->status = 'FAILED';
        $outbox->save();
      }
    }
  }

  private function saveToDb($request, $receiver, $sender)
  {
    $numOfButtons = empty(Helper::setting('numOfButtons')) ? 3 : Helper::setting('numOfButtons');
    $numOfLists = empty(Helper::setting('numOfLists')) ? 3 : Helper::setting('numOfLists');
    if (!empty($request->mediafile)) {
      if ($this->job_id !== $request->input('job_id')) {
        $this->job_id = $request->input('job_id');
        $user_id = auth()->user()->id;
        $file = Helper::normalize($request->mediafile->getClientOriginalName());
        $random = !empty($request->input('schedule')) && !empty($request->input('days')+$request->input('weeks')+$request->input('months')+$request->input('years')) ? 'recurring' : rand(111111, 999999);
        $mediafile = pathinfo($file, PATHINFO_FILENAME) . '-' . $random . '.' . pathinfo($file, PATHINFO_EXTENSION);
        $this->mediaurl = url("/users/{$user_id}/outbox/{$mediafile}");
        if (!file_exists(public_path("/users/{$user_id}/outbox/{$mediafile}"))) {
          $media_upload = $request->mediafile->move(public_path("/users/{$user_id}/outbox"), $mediafile);
        }
      }
    } elseif (!empty($request->input('mediaurlInput'))) {
      $this->mediaurl = $request->input('mediaurlInput');
      // $arrUrl = explode('/', $this->mediaurl);
      // $this->mediafile = end($arrUrl);
    }

    $outbox = new Outbox();
    $outbox->user_id = $request->input('user_id');
    $outbox->job_id = $request->input('job_id');
    $outbox->sender = $sender;
    if (str_ends_with($receiver['phone'], '@s.whatsapp.net') || str_ends_with($receiver['phone'], '@g.us') || str_ends_with($receiver['phone'], '@c.us')) {
      $outbox->receiver = $receiver['phone'];
    } else {
      $outbox->receiver = Formatter::pf($receiver['phone']);
    }
    $outbox->rec_name = $receiver['name'];
    // $outbox->mediafile = $this->mediafile;
    $outbox->mediaurl = $this->mediaurl;
    $outbox->msgtext = str_ireplace(
      ['{name}', '{phone}', '{email}', '{memo}', '{column1}', '{column2}', '{column3}', '{column4}', '{column5}'],
      [
        empty($receiver['name']) ? '' : $receiver['name'],
        empty($receiver['phone']) ? '' : $receiver['phone'],
        empty($receiver['email']) ? '' : $receiver['email'],
        empty($receiver['memo']) ? '' : $receiver['memo'],
        empty($receiver['column1']) ? '' : $receiver['column1'],
        empty($receiver['column2']) ? '' : $receiver['column2'],
        empty($receiver['column3']) ? '' : $receiver['column3'],
        empty($receiver['column4']) ? '' : $receiver['column4'],
        empty($receiver['column5']) ? '' : $receiver['column5'],
      ],
      $request->input('msgtext')
    );

    preg_match_all('/\{[^\}]*\}/', $outbox->msgtext, $matches);
    if (!empty($matches[0])) {
      foreach ($matches[0] as $match) {
        if (strpos($match, '|') > 0) {
          $match_no_brackets = str_replace(['{', '}'], [''], $match);
          $words = explode('|', $match_no_brackets);
          $outbox->msgtext = str_ireplace($match, $words[rand(0, count($words) - 1)], $outbox->msgtext);
        }
      }
    }

    if ($request->input('randomString') === 'uuid') {
      $outbox->msgtext = $outbox->msgtext . "\n\n" . Str::uuid();
    } elseif ($request->input('randomString') === 'inspiring') {
      $outbox->msgtext = $outbox->msgtext . "\n\n" . Inspiring::quote();
    }

    if (!empty($request->input('footer'))) {
      $outbox->msgtext = $outbox->msgtext . "\n\n" . '_' . $request->input('footer') . '_';
    }

    $outbox->msgtext = addslashes($outbox->msgtext);

    if (empty($request->input('schedule'))) {
      $outbox->schedule = Carbon::now();
      $outbox->recurring = null;
    } else {
      $outbox->schedule = $request->input('schedule');
      if (empty($request->input('days')+$request->input('weeks')+$request->input('months')+$request->input('years'))) {
        $outbox->recurring = null;
      } else {
        $outbox->recurring = $request->input('days').','.$request->input('weeks').','.$request->input('months').','.$request->input('years');
      }
    }
    $outbox->msgdelay = rand($request->input('min'), $request->input('max'));
    $outbox->save();

    if ($request->input('buttontype') === 'reply') {
      $data['replyButtons'] = [];
      for ($i = 1; $i <= $numOfButtons; $i++) {
        if (!empty($request->input('displayText' . $i))) {
          $arr = ['buttonId' => $request->input('responseText' . $i), 'buttonText' => ['displayText' => $request->input('displayText' . $i)], 'type' => 1];
          array_push($data['replyButtons'], $arr);
        }
      }
    } elseif ($request->input('buttontype') === 'template') {
      $data['templateButtons'] = [];
      for ($i = 1; $i <= $numOfButtons; $i++) {
        if (!empty($request->input('displayText' . $i))) {
          if (str_starts_with($request->input('responseText' . $i), 'http')) {
            $restype[$i] = 'url';
            $buttype[$i] = 'urlButton';
          } elseif (str_starts_with($request->input('responseText' . $i), '+')) {
            $restype[$i] = 'phoneNumber';
            $buttype[$i] = 'callButton';
          } else {
            $restype[$i] = 'id';
            $buttype[$i] = 'quickReplyButton';
          }
          $arr = ['index' => $i, $buttype[$i] => ['displayText' => $request->input('displayText' . $i), $restype[$i] => $request->input('responseText' . $i)]];
          array_push($data['templateButtons'], $arr);
        }
      }
    } elseif ($request->input('buttontype') === 'list') {
      $sectionTitle = 'startSection';
      $data['listButtons'] = [];
      $rows['rows'] = [];
      for ($i = 1; $i <= $numOfLists; $i++) {
        if ($sectionTitle === 'startSection' || $sectionTitle === $request->input('sectionTitle' . $i)) {
          $sectionTitle = $request->input('sectionTitle' . $i);
          if (!empty($request->input('rowTitle' . $i))) {
            $arrRow = ['title' => $request->input('rowTitle' . $i), 'description' => $request->input('description' . $i), 'rowId' => $request->input('rowId' . $i)];
            array_push($rows['rows'], $arrRow);
          }
        } else {
          $arrSection = ['title' => $sectionTitle, 'rows' => $rows['rows']];
          array_push($data['listButtons'], $arrSection);
          $rows['rows'] = [];
          $sectionTitle = $request->input('sectionTitle' . $i);
          if (!empty($request->input('rowTitle' . $i))) {
            $arrRow = ['title' => $request->input('rowTitle' . $i), 'description' => $request->input('description' . $i), 'rowId' => $request->input('rowId' . $i)];
            array_push($rows['rows'], $arrRow);
          }
        }
      }
      $arrSection = ['title' => $sectionTitle, 'rows' => $rows['rows']];
      array_push($data['listButtons'], $arrSection);
      $rows['rows'] = [];
    }

    $data['footerText'] = $request->input('footerText');
    $data['mainTitle'] = $request->input('mainTitle');
    $data['buttonText'] = $request->input('buttonText');
    $outbox->data = str_replace(',{"title":null,"rows":[]}', '', json_encode($data));
    $outbox->save();
  }

  public static function sendMessage($receiver, $msgtext, $sender, $mediaurl = null, $buttons = null, $outboxid = null)
  {
    $appurl = rtrim(config('app.url'), '/');
    $nodeurl = rtrim(config('app.node_url'), '/') . '/send';
    if (str_ends_with($receiver, '@s.whatsapp.net') || str_ends_with($receiver, '@g.us') || str_ends_with($receiver, '@c.us')) {
      $receiverWa = $receiver;
    } else {
      $receiverWa = Formatter::pf($receiver);
    }
    $token = Device::where('sender', $sender)->value('token');
    $data = [
      'receiver' => $receiverWa,
      'msgtext' => $msgtext,
      'sender' => $sender,
      'token' => $token,
      'appurl' => $appurl,
      'mediaurl' => $mediaurl,
      'buttons' => $buttons,
      'skipsave' => true,
    ];

    $response = Helper::curlPost($nodeurl, $data);
    return $response;
  }

  private static function sendScheduled($job_id, $unSubs)
  {
    $outboxes = Outbox::where('job_id', $job_id)
      ->where('status', 'SENDING')
      ->where('schedule', '<=', Carbon::now())
      ->whereNotIn('receiver', $unSubs)
      ->take(10)
      ->get();
    if (empty($outboxes[0])) return $job_id . ' is not ready.';
    foreach ($outboxes as $outbox) {
      $isWorkingHour = true;
      if (!empty($outbox?->device?->working_hours)) {
        $workingHours = json_decode($outbox->device->working_hours, true);
        $openHour = Carbon::createFromFormat('H:i', $workingHours[0], config('app.timezone'));
        $closedHour = Carbon::createFromFormat('H:i', $workingHours[1], config('app.timezone'));
        if ($closedHour < $openHour) $closedHour->addDay();
        $isWorkingHour = Carbon::now() > $openHour && Carbon::now() < $closedHour;
      }
      if (!$isWorkingHour) {
        Outbox::where('job_id', $job_id)->where('status', 'SENDING')->update(['status' => 'PENDING']);
        return;
      }
      if (empty($outbox?->sender) || empty($outbox?->receiver) || empty($outbox?->device)) {
        $outbox->status = 'FAILED(NO-SEND-RECV)';
        $outbox->save();
        continue;
      }
      if ($outbox->device->status !== 'ONLINE' && $outbox->device->autoswitch == 1) {
        $newSender = $outbox->user->devices->where('status', 'ONLINE')->value('sender');
        if (empty($newSender)) {
          $outbox->status = 'FAILED';
          $outbox->save();
          continue;
        } else {
          $outbox->sender = $newSender;
          $outbox->save();
        }
      }

      $device=Device::where('sender', $outbox->sender)->first();
      if ($device->busy) continue;
      try {
        $device->busy = true;
        $device->save();
        $response = self::sendMessage($outbox->receiver, $outbox->msgtext, $outbox->sender, $outbox->mediaurl, $outbox->data, $outbox->id);
        $res = json_decode($response);
        if (!empty($res->success)) {
          $outbox->status = 'SENT';
        } else {
          $outbox->status = isset($res->isonwa) && $res->isonwa === false ? 'FAILED(NOT WA)' : 'FAILED';
        }
        $outbox->save();
        $device->busy = false;
        $device->save();
        if (!empty($outbox->recurring)) {
          $arr = explode(',', $outbox->recurring);
          if (!empty($arr[3])) $outbox->schedule = (new Carbon($outbox->schedule))->addYears($arr[3]);
          if (!empty($arr[2])) $outbox->schedule = (new Carbon($outbox->schedule))->addMonths($arr[2]);
          if (!empty($arr[1])) $outbox->schedule = (new Carbon($outbox->schedule))->addWeeks($arr[1]);
          if (!empty($arr[0])) $outbox->schedule = (new Carbon($outbox->schedule))->addDayss($arr[0]);
          $outbox->status = 'PENDING';
          $outbox->save();
        }
        if (!empty($outbox->msgdelay)) {
          sleep($outbox->msgdelay);
        }
      } catch (Exception $e) {
        $outbox->status = 'FAILED';
        $outbox->save();
      }
    }

    Outbox::where('job_id', $job_id)
      ->where('status', 'SENDING')
      ->update(['status' => 'PENDING']);
    echo 'SUCCESS';
  }

  public function scheduledMsg(Request $request)
  {
    set_time_limit(0);
    $unSubs = self::subUnsub($request->job_id, $request->user_id);
    Outbox::where('job_id', $request->job_id)
    ->where('status', 'PENDING')
    ->where('schedule', '<=', Carbon::now())
    ->whereNotIn('receiver', $unSubs)
    ->update(['status' => 'SENDING']);
    self::sendScheduled($request->job_id, $unSubs);
  }

  private static function subUnsub($job_id, $user_id)
  {
    $unSubs = Subscriber::select('phone')
      ->where('user_id', $user_id)
      ->where('status', 0)
      ->get()
      ->toArray();
    Outbox::where('job_id', $job_id)
      ->where('status', 'PENDING')
      ->whereIn('receiver', $unSubs)
      ->update(['status' => 'FAILED(UNSUB)']);
    return $unSubs;
  }

  public function apiSend(Request $request)
  {
    $inputs = $request->all();
    $receiver = $inputs['receiver'] ?? null; // single
    $receivers = $inputs['receivers'] ?? null; // multi
    $msgtext = $inputs['msgtext'] ?? null;
    $mediaurl = $inputs['mediaurl'] ?? null;
    $delay_min = $inputs['delay_min'] ?? null; // multi
    $delay_max = $inputs['delay_max'] ?? null; // multi
    $token = $inputs['token'] ?? null;
    $sender = Device::where('token', $token)->value('sender');
    if (!$sender) return response(['success' => false, 'message' => 'Invalid token!']);

    if ($receivers) {
      if (!is_array($receivers)) json_decode($receivers, true);
      foreach ($receivers as $receiver) {
        Self::sendMessage($receiver, $msgtext, $sender, $mediaurl);
        $delay = rand($delay_min, $delay_max);
        sleep($delay ?? 1);
      }
    } else if ($receiver) {
      Self::sendMessage($receiver, $msgtext, $sender, $mediaurl);
    }
  }
}
