<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\View\View;
use App\Http\Helper\Helper;
use App\Models\ScheduleCampaign;
use Auth;

class ScheduleCampaignController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(): View
    {
        Helper::checkPermissions('campaigns_schedule');
        $page = "campaigns_schedule";
        $page_title = __('app.campaigns_schedule');
        $breadcrumbs = [
            __('app.campaigns_schedule') => route('schedule_campaigns.index'),
            __('app.manage') => '#'
        ];  
        return view('schedule_campaigns.index',compact('page', 'page_title', 'breadcrumbs'));
    }

    /**
    * Retrun JSON datatable data
    */
    public function getScheduleCampaigns(Request $request)
    {
        $result = ScheduleCampaign::select('schedule_campaigns.id', 'schedule_campaigns.name',
          'schedule_campaign_stats.start_datetime', 'schedule_campaigns.status', 'schedule_campaigns.total', 'schedule_campaigns.scheduled',
          'schedule_campaigns.sent', 'schedule_campaigns.created_at', 'schedule_campaigns.sending_server_ids', 'schedule_campaigns.sending_speed', 'schedule_campaign_stats.id as stats_id')
          ->leftJoin('schedule_campaign_stats', 'schedule_campaigns.id', '=', 'schedule_campaign_stats.schedule_campaign_id')
          ->app();

        $columns = ['schedule_campaigns.id', 'schedule_campaigns.name', 'schedule_campaign_stats.start_datetime', 'schedule_campaigns.id', 'schedule_campaigns.status','schedule_campaigns.total', 'schedule_campaigns.scheduled', 'schedule_campaigns.id', 'schedule_campaigns.created_at'];

        $data = Helper::dataFilters($request, $result, $columns);

        $total = $data['total'];
        $result = $data['result'];

        $scheduled_campaigns = $result->get();

        $data =  Helper::datatableTotals($total);

        foreach($scheduled_campaigns as $schedule) {
          $sending_speed = json_decode($schedule->sending_speed);
          $checkbox = "<input type=\"checkbox\" value=\"{$schedule->id}\" class=\"form-check-input\">";
          $actions = '<div class="btn-group">
            <button type="button" class="btn btn-outline-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">'.__('app.actions').'</button>';
          $actions .= '<ul class="dropdown-menu" style="">';

          if($schedule->status == 'Draft') {
            $actions .= '<li><a class="dropdown-item" href="'.route('schedule_campaigns.edit', $schedule->id).'"><i class="bi bi-pencil-square"></i> '.__('app.edit').'</a></li>';
          }

          $actions .= '<li><a class="dropdown-item" href="javascript:;" onclick="copyCampaign(\''.$schedule->id.'\', \''.__('app.copy_schedule'). '\')"><i class="bi bi-copy"></i> '.__('app.copy').'</a></li>';
         // $actions .= '<li><a href="javascript:;" onclick="viewModal(\'modal\', \''.route('detail.stat.campaign', [$schedule->stats_id, 'summary', 'stats.campaigns.summary_popup']).'\')"><i class="fa fa-area-chart"></i>'.__('app.summary').'</a></li>';

          if($schedule->status != 'Preparing' && $schedule->status != 'Draft') {
            $actions .= '<li><a class="dropdown-item" href="'.route('detail.stat.campaign', ['id' => $schedule->stats_id]).'" ><i class="bi bi-bar-chart"></i> '.__('app.analatics').'</a></li>';
          }

          if($schedule->status == 'RunningLimit' && !empty($sending_speed->limit)) {
            $actions .= '<li><a class="dropdown-item" href="javascript:;" onclick="runLimitedToUnlimited(\''.$schedule->id.'\', \''.__('app.run_limited_to_unlmited_msg'). '\')" ><i class="bi bi-rocket-takeoff"></i> '.__('app.run_as_unlimited').'</a></li>';
            $initial_limit = $sending_speed->initial_limit??$sending_speed->limit;
            $actions .= '<li><a class="dropdown-item" href="javascript:;" onclick="set2xSpeed(\''.$schedule->id.'\',\''.$sending_speed->limit.'\',\''.$initial_limit.'\', \''.__('app.set_speed_2x_msg'). '\')" ><i class="bi bi-rocket"></i> '.__('app.set_speed_2x_title').'</a></li>';
          }

          $actions .= '<li><a class="dropdown-item" class="dropdown-item text-danger" href="javascript:;" onclick="destroy(\''.$schedule->id.'\', \''.route('schedule_campaigns.destroy', [$schedule->id]).'\')"><i class="bi bi-trash"></i> '.__('app.delete').'</a></li>';
          $actions .= '</ul></div>';

          $status = '';
          if($schedule->status == 'Running' || $schedule->status == 'RunningLimit' || $schedule->status == 'Resume') {
            $status = "<a href='javascript:;'>
              <i class='bi bi-play-circle-fill text-success' id='play-{$schedule->id}' title='".__('app.play')."' onclick='pauseCampaign(\"{$schedule->id}\");' style='display:none;'></i>
              <i class='bi bi-pause-circle-fill text-warning' id='pause-{$schedule->id}' title='".__('app.pause')."' onclick='playCampaign(\"{$schedule->id}\");'></i>
              </a>";
            $schedule->status = 'Running'; // To overwrite RunningLimit to display
          } elseif($schedule->status == 'Paused') {
            $status = "<a href='javascript:;'>
              <i class='bi bi-play-circle-fill text-success' id='play-{$schedule->id}' title='".__('app.play')."' onclick='pauseCampaign(\"{$schedule->id}\");'></i>
              <i class='bi bi-pause-circle-fill text-warning' id='pause-{$schedule->id}' title='".__('app.pause')."' onclick='playCampaign(\"{$schedule->id}\");' style='display:none;'></i>
              </a>";
          } elseif($schedule->status == 'System Paused') {
            $status = '<a href="javascript:;" onclick="viewModal(\'modal\', \''.route('sending_server.status', ['id' => $schedule->sending_server_ids]).'\')"><i class="bi bi-info-circle-fill text-danger"></i></a>';
          }
          $status .= " <span id='status-{$schedule->id}'>{$schedule->status}</span>";

          $start_datetime = ($schedule->status == 'Preparing' || $schedule->status == 'Draft') ? '---' : Helper::datetimeDisplay($schedule->start_datetime);

          if($schedule->status != 'Draft')
            $spinner = '<div class="spinner-border spinner-border-sm text-dark" role="status"><spam class="visually-hidden"></span></div>';
          else 
            $spinner = '---';
          $progress = "( {$schedule->sent} / {$schedule->scheduled} ) " . Helper::getPercentage($schedule->sent, $schedule->scheduled);

          $scheduled = '<a class="link-info" href="javascript:;" onclick="viewModal(\'modal\', \''.route('scheduled.detail.campaign', ['id' => $schedule->id]).'\')">'.$schedule->scheduled.'</a>';

          $name = $schedule->status == 'System Paused' ?  '<a href="javascript:;" onclick="swal(\''.$schedule->name.'\')"><i class="fa fa-info-circle text-red"></i></a> '.$schedule->name : $schedule->name;
          
          $limit = ($sending_speed->speed == 'unlimited') ? __('app.unlimited') : $sending_speed->limit;

          $name = '<a class="link-info" href="javascript:;" onclick="viewModal(\'modal\', \''.route('schedule_campaigns.show', [$schedule->id]).'\')">'.$schedule->name.'</a>';

          $data['data'][] = [
            "DT_RowId" => "row_{$schedule->id}",
            $checkbox,
            $name ?? '--',
            $start_datetime,
            $limit,
            $status,
            $schedule->total == null ? $spinner : $schedule->total,
            // $schedule->status != 'Scheduled' if no one scheduled and there is 0
            ($schedule->scheduled == null && $schedule->status != 'Scheduled') ? $spinner : $scheduled,
            $schedule->total == null ? $spinner : $progress,
            Helper::datetimeDisplay($schedule->created_at),
            $actions
          ];
        }
        echo json_encode($data);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create(): View
    {
        Helper::checkPermissions('campaigns_schedule');
        $page = "campaigns_schedule";
        $page_title = __('app.schedule_campaign');
        $breadcrumbs = [
            __('app.campaigns_schedule') => route('schedule_campaigns.index'),
            __('app.schedule_campaign') => '#'
        ];

        return view('schedule_campaigns.create',compact('page', 'page_title', 'breadcrumbs'));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): RedirectResponse
    {
        $data = $this->_scheduleCampaignData($request);        
        $schedule_campaign = ScheduleCampaign::create($data);

        if($data['status'] != 'Draft') {
          activity('schedule')->withProperties(['app_id' => Auth::user()->app_id])->log(__('app.campaign') . " ({$request->name}) ". __('app.log_schedule'));
          
          \App\Jobs\CampaignPrepare::dispatch($schedule_campaign->id)
          ->delay(now()->addSeconds(10));
        } else {
          activity('schedule')->withProperties(['app_id' => Auth::user()->app_id])->log(__('app.campaign') . " ({$request->name}) ". __('app.log_schedule_update'));
        }

        if($data['operation'] == 'save')
            return redirect()->route('schedule_campaigns.index')
            ->with('success', ($request->name . ' ' . __('app.draft_created_successfully')));
        else
            return redirect()->route('schedule_campaigns.index')
            ->with('success', ($request->name . ' ' . __('app.scheduled_successfully')));
    }

    public function edit(int $id): View
    {
        Helper::checkPermissions('campaigns_schedule');
        $page = "campaigns_schedule";
        $page_title = __('app.schedule_campaign');
        $breadcrumbs = [
            __('app.campaigns_schedule') => route('schedule_campaigns.index'),
            __('app.schedule_campaign') => '#'
        ];
        $schedule = ScheduleCampaign::find($id);

        return view('schedule_campaigns.edit',compact('page', 'page_title', 'breadcrumbs', 'schedule'));
    }
    
    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, int $id): RedirectResponse
    {
        $schedule = ScheduleCampaign::find($id);
        $data = $this->_scheduleCampaignData($request);
        $schedule->fill($data)->save();

        if($data['status'] != 'Draft') {
          activity('schedule')->withProperties(['app_id' => Auth::user()->app_id])->log(__('app.campaign') . " ({$request->name}) ". __('app.log_schedule'));

          \App\Jobs\CampaignPrepare::dispatch($id)
          ->delay(now()->addSeconds(10));
        } else {
          activity('schedule')->withProperties(['app_id' => Auth::user()->app_id])->log(__('app.campaign') . " ({$request->name}) ". __('app.log_schedule_update'));
        }

        if($data['operation'] == 'save')
            return redirect()->route('schedule_campaigns.index')
            ->with('success', ($request->name . ' ' . __('app.draft_updated_successfully')));
        else
            return redirect()->route('schedule_campaigns.index')
            ->with('success', ($request->name . ' ' . __('app.scheduled_successfully')));
    }

    public function show($id)
    {
        $scheduled = ScheduleCampaign::select('schedule_campaigns.*',
          'schedule_campaign_stats.start_datetime','schedule_campaign_stats.end_datetime', 'schedule_campaign_stats.id as stats_id')
          ->leftJoin('schedule_campaign_stats', 'schedule_campaigns.id', '=', 'schedule_campaign_stats.schedule_campaign_id')
          ->where('schedule_campaigns.id',$id)
          ->app()
          ->first();
        return view('schedule_campaigns.view')->with(compact('scheduled'));
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(int $id, Request $request): JsonResponse
    {
        if(!empty($request->action)) {
            $ids = array_values($request->ids);
            $names = json_encode(array_values(ScheduleCampaign::whereIn('id', $ids)->pluck('name')->toArray()));
            $destroy = ScheduleCampaign::whereIn('id', $ids)->delete();
        } else {
            $names = ScheduleCampaign::whereId($id)->value('name');
            $destroy = ScheduleCampaign::destroy($id);
        }
        activity('delete')->withProperties(['app_id' => Auth::user()->app_id])->log(__('app.scheduled_campaigns') . " ({$names}) ". __('app.log_delete'));

        $data = [
          'success' => true,
          'message' => __('app.deleted_successfully')
        ];

        return response()->json($data, 200);
    }

    /**
    * Retrun data for store or update
    */
    private function _scheduleCampaignData($request): Array
    {
        $input = $request->except('_token');
        $input['list_ids'] = implode(',', $input['list_ids']);
        $input['sending_server_ids'] = implode(',', $input['sending_server_ids']);
        $input['limit'] = empty($input['limit']) ? 1000 : $input['limit'];

        $carbon = new \Carbon\Carbon();
        if($input['send'] == 'now') {
          $input['send_datetime'] = $carbon->now();
        } else {
            // It has the correct value as per UTC for a calander
         $send_datetime = date('Y-m-d H:i:s', strtotime("{$input['db_send_datetime']}"));
          // Convert future datetime into UTC datetime
          $offsetSeconds =  $carbon->now(Auth::user()->time_zone)->getOffset();
          $input['send_datetime'] = \Carbon\Carbon::parse($send_datetime, config('app.timezone'))->subSeconds($offsetSeconds);
        }
        $input['sending_speed'] = json_encode(['speed'=>$input['speed'], 'limit'=>$input['limit'], 'duration'=>$input['duration'], 'intital_limit'=>$input['limit'], 'running_speed'=>'1X']);

        if($input['from_detail'] == 'custom') {
            $input['from_detail_custom'] = json_encode([
                'from_name' => $input['from_name'],
                'from_email' => ($input['from_email_part1'] . '@' . $input['from_email_part2']),
                'reply_email' => $input['reply_email']
            ]);
        }

        // For time limit the threads must be 1; no parallels sending required
        $input['status'] = ($input['operation'] == 'save') ? 'Draft' : 'Preparing';
        $input['name'] = Helper::encodeString($input['name']);
        $input['email_subject'] = Helper::encodeString($input['email_subject']);
        $input['content'] = Helper::encodeString($input['content_html']);
        $input['threads'] = !empty($input['limit']) ? 1 : config('custom.threads');
        $input['user_id'] = Auth::user()->id;
        $input['app_id'] = Auth::user()->app_id;
        return $input;
    }

    /**
    * Retrurn view for scheduled detail
    */
    public function getScheduledDetail($id) {
        $schedule = ScheduleCampaign::findOrFail($id);

        $name = $schedule->name;
        $scheduled_detail = json_decode($schedule->scheduled_detail);
        return view('schedule_campaigns.scheduled_detail')->with(compact('name', 'scheduled_detail'));
    }

    /**
    * Update status
    */
    public function updateScheduleStatus(Request $request, $id) {
        $status = $request->status;
        // For running status need to check either set to Running or RunningLimit(hourly)
        if($status == 'Resume') {
          $sending_speed = ScheduleCampaign::whereId($id)->value('sending_speed');
          if(json_decode($sending_speed)->limit) {
            $status = 'RunningLimit';
          }
        }
        ScheduleCampaign::whereId($id)->update(['status' => $status]);
    }

    /**
    * Set campaign to run limited to unlimited.
    */
    public function limitedToUnlimited(Request $request) {
        $sending_speed = json_encode([
          'speed' => 'unlimited',
          'limit' => null,
          'duration' => 'hour'
        ]);
        ScheduleCampaign::whereId($request->id)->update([
          'status' => 'Resume',
          'send_datetime' => \Carbon\Carbon::now(),
          'thread_no' => 1,
          'sending_speed' => $sending_speed,
          ]
        );

        // Update stat table also
        \App\Models\ScheduleCampaignStat::whereScheduleCampaignId($request->id)->update([
          'sending_speed' => $sending_speed,
          ]
        );
    }

    /**
    * Set campaign to run limited to unlimited.
    */
    public function set2xSpeed(Request $request) {

        $new_limit = $request->limit*2;
        $sending_speed = json_encode([
          'speed' => 'limited',
          'limit' => $new_limit,
          'duration' => 'hour',
          'initial_limit' => $request->initial_limit,
          'running_speed' => '2X'
        ]);
        ScheduleCampaign::whereId($request->id)->update([
          'sending_speed' => $sending_speed,
          ]
        );

        // Update stat table also
        \App\Models\ScheduleCampaignStat::whereScheduleCampaignId($request->id)->update([
          'sending_speed' => $sending_speed,
          ]
        );
    }


    /**
    * Retrun HTML data of a template
    */
    public function copy(int $id): RedirectResponse
    {
        Helper::checkPermissions('campaigns_schedule'); // check user permission
        $schedule = ScheduleCampaign::find($id);
        $schedule->name = $schedule->name .' - copy ';
        $schedule->total_threads = 0;
        $schedule->thread_no = 0;
        $schedule->total = 0;
        $schedule->scheduled = 0;
        $schedule->sent = 0;
        $schedule->scheduled_detail = null; 
        $schedule->status = 'Draft';
        $schedule->user_id = Auth::user()->id;
        $scheduled = $schedule->replicate();
        $scheduled->save();
        activity('schedule')->withProperties(['app_id' => Auth::user()->app_id])->log(__('app.schedule') . " ({$schedule->name}) ". __('app.log_copy'));

        return redirect()->route('schedule_campaigns.index')
            ->with('success', ($schedule->name . ' ' . __('app.copied_successfully')));
    }

    /**
    * Retrun HTML data of a template
    */
    public function getHTMLContent(int $id)
    {
        $content = ScheduleCampaign::whereId($id)->app()->value('content');
        return view('broadcasts.view')->with('content_html', $content);
    }

    /**
    * Initiate send campaign process via scheduled command
    */
    public function runCampaigns($id = null, $thread_no = 1)
    {
        if (!empty($id)) {
          $send = \Artisan::call('run:campaigns', [
            'id'        => $id,
            'thread_no' => $thread_no
          ]);
        } else {
          $schedules = ScheduleCampaign::whereIn('status', ['Scheduled', 'RunningLimit', 'Resume'])
            ->where('send_datetime', '<=', \Carbon\Carbon::now())
            ->orderBy('id', 'desc')
            ->get();
          if(count($schedules) > 0) {
            foreach($schedules as $schedule) {
              $this->_processCampaignParallels($schedule);
            }
          }
        }
    }

    /**
    * Send parallel request to execute the campaign
    */
    private function _processCampaignParallels($schedule)
    {
       $app_url = Helper::getAppURL();

        // Need to start thead_no with 1 instead 1 as default set 0
        $thread_no = $schedule->thread_no == 0 ? 1 : $schedule->thread_no;
        $threads = $thread_no + $schedule->threads;
        // If set to send hourly then need to send only one thread with thread no
        if(json_decode($schedule->sending_speed)->speed == 'limited') {
          $url = $app_url."/run_campaigns/{$schedule->id}/{$thread_no}";
          Helper::getUrl($url);
        } else  {
          for($i=$thread_no; $i<$threads; $i++) {
            $url = $app_url."/run_campaigns/{$schedule->id}/{$i}";
            Helper::getUrl($url);
          }
        }
    }

    public function scheduledEvents(): JsonResponse
    {
        $schedules = ScheduleCampaign::select('schedule_campaigns.id',
          'schedule_campaign_stats.start_datetime','schedule_campaign_stats.end_datetime')
          ->leftJoin('schedule_campaign_stats', 'schedule_campaigns.id', '=', 'schedule_campaign_stats.schedule_campaign_id')
          ->app()
          ->get();

        $events = array();
        foreach($schedules as $schedule) {
            $carbon = new \Carbon\Carbon($schedule->start_datetime);
            $start = $carbon->setTimezone(\Auth::user()->timezone);

            $carbon = new \Carbon\Carbon($schedule->end_datetime);
            $end = $carbon->setTimezone(\Auth::user()->timezone);
            $events[] = [
                'id' => $schedule->id,
                'start' => $start,
                'end' => $end,
            ];
        }
        return response()->json($events);
    }
}
