<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use League\Csv\Writer;
use App\Models\SplitTest;
use DB;
use App\Http\Helper\Helper;

class SplitTestPrepare extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'prepare:split-test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Prepare the campaigns for split test';

    private $processed = 0;
    private $inactive =  0;
    private $unsubscribed = 0;
    private $suppressed = 0;
    private $bounced = 0;
    private $spammed = 0;
    private $duplicates = 0;
    private $batch_no = 0;
    private $i = 0;
    private $batch_size = 500;
    private $old_email = null;
    private $writer = null;

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $split_tests = SplitTest::whereScheduled(0)->get();

        foreach($split_tests as $split_test) {
          if(json_decode($split_test->sending_speed)->speed == 'limited') {
            $email_per_batch = json_decode($split_test->sending_speed)->limit;
          } else {
            $email_per_batch = $this->batch_size;
          }

          $path_split_test = str_replace('[user-id]', $split_test->user_id, config('custom.path_split_test'));
          $path_split_test .= $split_test->id;

          $list_ids = json_decode($split_test->list_ids);

          // without distinct
          $total = DB::table('contacts')->whereIn('list_id', $list_ids)->count();

          // total percent sent to check 
          $total_percent_sent = Helper::getPercentOfData($split_test->decision_percentage, $total);

          // update total
          SplitTest::whereId($split_test->id)->update([
            'total' => $total,
            'percentage_sent' => $total_percent_sent
          ]);

          // Create record for split_test_stats table also
          $schedule_by = \App\Models\User::getUserValue($split_test->user_id, 'name');
          $opens_clicks = json_encode([
              "total_opens" => 0,
              "unique_opens" => 0,
              "total_clicks" => 0,
              "unique_clicks"=> 0
          ]);
          $stat_data = [
            'split_test_id'   => $split_test->id,
            'split_test_name' => $split_test->name,
            'winning_criteria' => $split_test->winning_criteria,
            'decision_percentage' => $split_test->decision_percentage,
            'action'          => $split_test->action,
            'action_data'     => $split_test->action_data,
            'schedule_by'     => $schedule_by,
            'threads'         => $split_test->threads,
            'total'           => $total,
            'scheduled'       => 0,
            'sent'            => 0,
            'opens_clicks'    => $opens_clicks,
            'start_datetime'  => $split_test->send_datetime,
            'sending_speed'   => $split_test->sending_speed,
            'app_id'          => $split_test->app_id,
            'user_id'         => $split_test->user_id,
          ];
          $split_test_stat = \App\Models\SplitTestStat::create($stat_data);

          \App\Models\Contact::whereIn('list_id', $list_ids)
            ->with('list')
            ->with('customFields')
            ->orderBy('email')
            ->orderBy('id')
            ->chunk($this->batch_size, function ($contacts) use ($email_per_batch, $path_split_test, $split_test, $total_percent_sent) {

              $attributes = json_decode($split_test->attributes);
              $from_detail = $attributes->from_detail;

              foreach ($contacts as $contact) {
                // Check inactive
                if($contact->active == 'No') { $this->inactive++; continue; }

                // Check unsubscribed
                if($contact->unsubscribed == 'Yes') { $this->unsubscribed++; continue; }

                // Check suppressed
                if(Helper::isSuppressed($contact->email, $split_test->app_id, $contact->list_id)) { $this->suppressed++; continue; }

                // Skip duplicates; group by clause mantain same emails consecutives
                if($contact->email == $this->old_email) { $this->duplicates++; continue; }

                $this->old_email = $contact->email; // Keep old email record to compare next time 


                // Check bounced
                if($contact->is_bounced) { $this->bounced++; continue; }

                // Check spammed
                $is_spammed = DB::table('global_spams')
                  ->whereEmail($contact->email)
                  ->exists();
                if($is_spammed)  { $this->spammed++; continue; }

                if($this->batch_no == 0 || $this->i >= $email_per_batch) {
                  // Need to start file with 1
                  $this->batch_no++;
                  Helper::dirCreateOrExist($path_split_test); //Create dir if not exist
                  $file = $path_split_test.DIRECTORY_SEPARATOR.$this->batch_no.'.csv';
                  // 5 sec break;
                  sleep(5);

                  // Sometime it restart to write the file so handel it
                  if(file_exists($file)) exit;

                  $this->writer = Writer::createFromPath($file, 'w+'); // Create a .csv file to write data
                  //chmod($file, 0777);  // File Permission
                  $data = [
                    'ID', 
                    'EMAIL',
                    'FORMAT',
                    'LIST',
                    'FROM_NAME',
                    'FROM_EMAIL',
                    'REPLY_EMAIL',
                  ];
                  $this->writer->insertOne($data); // Write data into file
                  $this->i = 0;

                  // Need to start campaign when 1 file ready to send
                  if($this->batch_no > 1) {
                    SplitTest::whereId($split_test->id)->update([
                      'total_threads' => $this->batch_no
                    ]);

                    // Only need to make schedule for when 1st complete
                    if($this->batch_no == 2) {
                      SplitTest::whereId($split_test->id)->update([
                        'status' => 'Scheduled'
                      ]);
                    }
                  }
                }

                if($from_detail == 'custom') {
                  $from_detail_custom = json_decode($attributes->from_detail_custom);
                  $from_name = $from_detail_custom->from_name;
                  $from_email = $from_detail_custom->from_email;
                  $reply_email = $from_detail_custom->reply_email;
                } elseif($from_detail == 'list') {
                  $from_name = $contact->list->from_name;
                  $from_email = $contact->list->from_email;
                  $reply_email = $contact->list->reply_email;
                } else {
                  $from_name = $from_email = $reply_email = '';
                }

                $data = [
                  $contact->id,
                  $contact->email,
                  $contact->format,
                  Helper::decodeString($contact->list->name),
                  Helper::decodeString($from_name),
                  $from_email,
                  $reply_email,
                ];
                $this->writer->insertOne($data); // Write data into file
                $this->i++;
                $this->processed++;

                // Increment in scheduled
                $split_test->increment('scheduled');

                // break for second loop
                if($split_test->action == 'show_results' && $this->processed >= $total_percent_sent) {
                  break;
                }
              }
          });

          $scheduled_detail = [
            'Total'        => $total,
            'Scheduled'    => $this->processed,
            'Inactive'     => $this->inactive,
            'Unsubscribed' => $this->unsubscribed,
            'Duplicates'   => $this->duplicates,
            'Suppressed'   => $this->suppressed,
            'Bounced'      => $this->bounced,
            'Spammed'      => $this->spammed,
          ];

          // If there is only 1 batch then upper condtion will not execute
          if($this->batch_no == 1) {
            SplitTest::whereId($split_test->id)->update([
              'status' => 'Scheduled'
            ]);
          }

          // Update split_test table 
          SplitTest::whereId($split_test->id)->update([
            'scheduled' => $this->processed,
            'total_threads'   => $this->batch_no,
            'scheduled_detail' => json_encode($scheduled_detail),
          ]);

          // Update split_test_stats table 
          \App\Models\SplitTestStat::whereId($split_test_stat->id)->update([
            'scheduled_detail' => json_encode($scheduled_detail),
            'scheduled'        => $this->processed,
          ]);

        } // end foreach split_tests
      }
}
