<?php
namespace App\Modules\Mobile\Supervisor;

use App\Models\Company;
use App\Models\Projects;
use App\Models\ProjectWorkersTimesheet;
use Carbon\Carbon;
use Carbon\CarbonPeriod;

use App\Traits\TimeSheetTrait;
use App\Traits\UserTraits;
use App\Traits\CreateMobileNotificationTraits;
use App\Traits\ValidatorTraits;

use App\Events\Company\ApprovedTimesheetEvent;
use App\Models\CompanyWorkerTimesheet;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class Tasks {
	
	use ValidatorTraits, TimeSheetTrait, UserTraits, CreateMobileNotificationTraits;

	public function getTasks($payload) 
	{
		$userData = $this->getCurrentUser();

		$company = Company::select('name','street_address','city','state','zipcode')->where('id', $userData->company_id)->get();
		$offset = $payload->offset ?: 0;
		
		$user_id = $userData->id;
		$filters = json_decode($payload->filters);

		$limit = $payload->limit;

		$page = $payload->page ?: 0;

		$Projects =  Projects::select(  
			'projects.id as project_id',
			'projects.name as project_name',
			'companies.name as company_name',
			'projects.location',
			'project_supervisors.date_from as date_from',
			'project_supervisors.date_to as date_to',
		) 
			->join('project_supervisors', 'project_supervisors.project_id','=','projects.id')
			->join('companies','companies.id','=','projects.company_id')
			->where('project_supervisors.user_id', $user_id)
			->whereRaw('projects.date_end >= now()')
			->whereNull('project_supervisors.deleted_at')
			->orderBy('company_name', 'desc')
			->get();

		$Schedules   = [];
		$itemCounter = $offset;
		$dateOptions = $this->GeneratePeriod(($filters && property_exists($filters, 'date')) ? $filters->date : false, $Projects, 'pending');

		$date = $dateOptions['period']->toArray();

		foreach ($date as $day) 
		{
			if ($itemCounter == $limit - 1 || !isset($day)) 
			{
				break 1;
			}
		
			if ($Projects && count($Projects) != 0) 
			{
				$projectDetails    = [];
				$dayProjectCounter = 0;
				
				foreach ($Projects as $project) 
				{
					// if (!isset($day)) {
					// 	break 2;
					// }
					$date_from = Carbon::parse(Carbon::parse($project->date_from)->toDateString());
					$date_to   = Carbon::parse(Carbon::parse($project->date_to)->toDateString());
					$current   = Carbon::parse($day->toDateString());

					if ($this->DateBetweenDates($current,$date_from,$date_to)) 
					{  
						$status = $this->getScheduleSummary($project->project_id, $day);
						$dayProjectCounter++;

						array_push(
							$projectDetails, 
							[
								'summary'      => $status,
								'company_name' => $project->company_name,
								'project_name' => $project->project_name,
								'project_id'   => $project->project_id,
								'location'     => json_decode($project->location)
							]
						);
					}
				}

				if ($dayProjectCounter == 0) 
				{
					array_push(
						$Schedules, 
						[
							"id"       => $itemCounter,
							"date"     => $day,
							"projects" => 
							[
								"project_name" => "Stand by",
								"company_name" => $company[0]->name,
								"project_id"   => 1,
								"address"      => "Unavailable",
								"location"     => 
								[
									"street_address" => $company[0]->street_address,
									"city"           => $company[0]->city,
									"state"          => $company[0]->state,
									"zipcode"        => (int)$company[0]->zipcode
								]
							]
						]	
					);
				} 
				else 
				{
					array_push(
						$Schedules, 
						[ 
							'id'       => $itemCounter,
							"projects" => $projectDetails,
							"date"     => $day 
						]
					);
				}
			}
			
			$itemCounter++;

		}
		return response()->json(
			[
				'hits' => $Schedules,
				'length' => count($Schedules),
				'current_page' => $page,
				'next_page' => $page + 1,
				'current_offset' => $itemCounter
			]
		);
	}

	public function historySchedules($payload) 
	{
		$userData = $this->getCurrentUser();

		$company =  Company::select('name','street_address','city','state','zipcode')->where('id', $userData->company_id)->get();
		$offset = $payload->offset ?: 0; 
		
		$user_id = $userData->id;
		$filters = json_decode($payload->filters);

		$date_hired = Carbon::parse($userData->date_hired);
	
		$limit = $payload->limit;
		$page = $payload->current_page ?: 0;

		$projects = Projects::select(  
				'projects.id as project_id', 
				'projects.name as project_name',
				'companies.name as company_name',
				'projects.location',     
				'project_supervisors.date_from as date_from',
				'project_supervisors.date_to as date_to',
			) 
			->join('project_supervisors', 'project_supervisors.project_id','=','projects.id')
			->join('companies','companies.id','=','projects.company_id')
			->where('project_supervisors.user_id', $user_id)
			->whereNull('project_supervisors.deleted_at')
			->get();
		
		$dateOptions = $this->GeneratePeriod(($filters && property_exists($filters,'date'))? $filters->date :false ,$projects,'history');

		$dates = array_reverse($dateOptions['period']->toArray());

		$Schedules = [];

		$itemCounter = $offset;

		foreach ($dates as $day) 
		{
			if ($itemCounter == $limit - 1) 
			{
				break 1;
			}

			$projectDetails = [];
			$dayProjectCounter = 0;
	
			if ($projects && count($projects) != 0) 
			{
				foreach ($projects as $project ) 
				{
					$date_from = Carbon::parse(Carbon::parse($project->date_from)->toDateString());
					$date_to   = Carbon::parse(Carbon::parse($project->date_to)->toDateString());
					$current   = Carbon::parse($day->toDateString());

					//** Log::info("Current Date : {$current}, Date From : {$date_from}, Date To : {$date_to}, Is Between or Equal : {$this->DateBetweenDates($current,$date_from,$date_to)}");

					if ($current->gte($date_hired)) 
					{  
						if ($this->DateBetweenDates($current,$date_from,$date_to)) 
						{  
							$dayProjectCounter++;
							$summary = $this->getScheduleSummary($project->project_id,$current);
						
							if ($summary["overall_status"] != "Pending") 
							{
								array_push(
									$projectDetails, 
									[
										'summary'      => $this->getScheduleSummary($project->project_id,$current),
										'company_name' => $project->company_name,
										'project_name' => $project->project_name,
										'project_id'   => $project->project_id,
										'location'     => json_decode($project->location)
									]
								);        
							}      
						}
					}
				}
			}

			if ($dayProjectCounter == 0) 
			{
				array_push(
					$Schedules, 
					[
						"id"       => $itemCounter,
						"date"     => $day,
						"projects" => 
						[
							"project_name" => "Stand by",
							"company_name" => $company[0]->name,
							"project_id"   => 1,
							"address"      => "Unavailable",
							"location"     => 
							[
								"street_address" => $company[0]->street_address,
								"city"           => $company[0]->city,
								"state"          => $company[0]->state,
								"zipcode"        => (int)$company[0]->zipcode
							]
						]  
					]
				);
			} 
			else 
			{
				if (count($projectDetails) != 0) 
				{
					array_push( 
						$Schedules, 
						[
							'id'       => $itemCounter,
							"projects" => $projectDetails,
							"date"     => $day
						]
					);
				}
			}
			$itemCounter++;
		}
		return response()->json(
			[
				'hits'           => $Schedules,
				'period'         => $dateOptions,
				'date_hired'     => $date_hired,
				'length'         => count($Schedules),
				'current_page'   => $page,
				'next_page'      => $page + 1,
				'current_offset' => $itemCounter
			]
		);
	}

	public function getTasksByRange($payload) {
		//UserResource::collection(User::all())
		// $user_id = $this->getCurrentUser()[0]->user_id;
		$user_id = Auth::user()->id;
		//UserResource::collection(User::all())

		$date = [
			'to'   => $payload->date['to'],
			'from' => $payload->date['from']
		];
		
		$Projects = Projects::select(
			'projects.id as project_id',
			'projects.name as project_name',
			'companies.name as company_name',
			'projects.company_id',
			'projects.location',

			'project_supervisors.date_from as date_from',
			'project_supervisors.date_to as date_to',
		) 
			->join('project_supervisors', 'project_supervisors.project_id','=','projects.id')
			->join('companies','companies.id','=','projects.company_id')
			->where('project_supervisors.user_id', $user_id)
			->whereNull('project_supervisors.deleted_at')
			->get();
		
		// return response()->json($Projects);

		$Schedules = [];
		if (count($Projects) == 1) {
			$days_count =  Carbon::parse(Carbon::parse($date['from']))->diffInDays(Carbon::parse($date['to']));
			if ($days_count >= 11) {
				$period = CarbonPeriod::create(Carbon::parse($date['from']), Carbon::parse($date['to']));
				for($x = 0; $x <= 9; $x++) {
					$schedule = [
						'id'           => $x,
						'summary'      => $this->getScheduleSummary($Projects[0]->project_id,$period->toArray()[$x]),
						'company_name' => $Projects[0]->company_name,
						'project_name' => $Projects[0]->project_name,
						'project_id'   => $Projects[0]->project_id,
						'location'     => json_decode($Projects[0]->location),
					];
					array_push( $Schedules, [$schedule,"date"=>$period->toArray()[$x] ]);
				}
			}
		} else if (count($Projects) > 1) {
			$days_count = Carbon::parse(Carbon::parse($date['from']))->diffInDays(Carbon::parse($date['to']));
			if ($days_count >= 11) { 
				$period =CarbonPeriod::create(Carbon::parse($date['from']), Carbon::parse($date['to'])); 
				for ($x = 0; $x <= $days_count -1; $x++) {
					$project = [];
					for ($y =0; $y <= count($Projects)-1; $y++) {
						// return $period[$x]->toArray()[$x]->between(Carbon::parse($Projects[$y]->date_from),Carbon::parse( $Projects[$y]->date_to));
						if($period->toArray()[$x]->between(Carbon::parse($Projects[$y]->date_from),Carbon::parse( $Projects[$y]->date_to))) {
							array_push($project,[
								'summary'      => $this->getScheduleSummary($Projects[$y]->project_id,$period->toArray()[$x]),
								'company_name' => $Projects[$y]->company_name,
								'project_name' => $Projects[$y]->project_name,
								'project_id'   => $Projects[$y]->project_id,
								'location'     =>  json_decode($Projects[0]->location)
							]);
						}
					}
					array_push($Schedules, [
						'id'       => $x,
						"projects" => $project,
						"date"     => $period->toArray()[$x]
					]);
				}
			} else{
				$period = CarbonPeriod::create(Carbon::parse($date['from']), Carbon::parse($date['to'])); 
				for ($x = 0; $x <= count($period->toArray()) - 1; $x++) { 
					$project = [];
					for($y = 0; $y <= count($Projects)-1; $y++) {
					//   return $period[$x]->toArray()[$x]->between(Carbon::parse($Projects[$y]->date_from),Carbon::parse( $Projects[$y]->date_to));
						if($period->toArray()[$x]->between(Carbon::parse($Projects[$y]->date_from),Carbon::parse( $Projects[$y]->date_to))) {
							array_push($project,[
								'summary'      => $this->getScheduleSummary($Projects[$y]->project_id,$period->toArray()[$x]),
								'company_name' => $Projects[$y]->company_name,
								'project_name' => $Projects[$y]->project_name,
								'project_id'   => $Projects[$y]->project_id,
								'location'     =>  json_decode($Projects[0]->location)
							]);
						}
					}
					array_push($Schedules, [
						'id'       => $x,
						"projects" => $project,
						"date"     => $period->toArray()[$x]
					]);
				}
			}
		}
		// return $Schedules;
		return response()->json($Schedules);
	}

	public function getEmployeesByDate($payload) 
	{

		$worker_hours = $this->getWorkerTasksByProject($payload->project_id,$payload->date);
		$overall_status = 'Done';
		$Pending_count = 0;
		$Submitted_count = 0;

		for ($x = 0; $x <= count($worker_hours) - 1; $x++) 
		{
			if (
				$worker_hours[$x]->status == 'pending' ||
				$worker_hours[$x]->status == 'request modification' ||
				$worker_hours[$x]->status == 'absent'
			) 
			{
				$overall_status = 'Pending';
				$Pending_count++;
			} 
			elseif (
				$worker_hours[$x]->status == 'approved' ||
				$worker_hours[$x]->status == 'confirmed absent' ||
				$worker_hours[$x]->status == 'submitted'
			) 
			{
				$Submitted_count++;
			}
			$worker_hours[$x]->clock_in  = Carbon::createFromTimeString($worker_hours[$x]->clock_in )->format('g:i A');
			$worker_hours[$x]->clock_out = Carbon::createFromTimeString($worker_hours[$x]->clock_out)->format('g:i A');
		}
		for ($x = 0; $x <= count($worker_hours) - 1; $x++) {
			if ($worker_hours[$x]->status == 'pending' || $worker_hours[$x]->status =='request modification') {
				$overall_status = 'Pending';
			}
		}
		return response()->json([
			"schedules"      => $worker_hours,
			'overall_status' => $overall_status
		]);
	}

	public function approveInput($payload) 
	{
		$supervisor_name = $this->getCurrentUserName();

		$updateDetails =
		[
			'approved_by'                  => $supervisor_name,
			'request_modification_message' => null,
			'status'                       => 'approved',
		];

		$companyWorkerTimesheet = CompanyWorkerTimesheet::find($payload->schedule_id);
		$projectWorkerTimesheet = ProjectWorkersTimesheet::query()
			->select(
				'project_workers_timesheet.id as id'
			)
			->join('assigned_workers', 'assigned_workers.id', '=', 'project_workers_timesheet.project_worker_id')
			->where(
				[
					['project_workers_timesheet.worker_id',  	'=', $companyWorkerTimesheet->worker_id],
					['project_workers_timesheet.status', 		'=', $companyWorkerTimesheet->status],
					['project_workers_timesheet.total_hours', 	'=', $companyWorkerTimesheet->total_hours],
					['project_workers_timesheet.date', 			'=', $companyWorkerTimesheet->date],
					['project_workers_timesheet.rate', 			'=', $companyWorkerTimesheet->rate],
					['assigned_workers.project_id', 			'=', $companyWorkerTimesheet->reference_id]
				]
			)->first();

		$projectWorkerTimesheet = ProjectWorkersTimesheet::find($projectWorkerTimesheet->id);

		if ($projectWorkerTimesheet != null)
		{
			DB::transaction( function() use ($updateDetails, $projectWorkerTimesheet, $companyWorkerTimesheet)
				{
					$projectWorkerTimesheet->update($updateDetails); 
					
					$companyWorkerTimesheet->update($updateDetails);
					event(new ApprovedTimesheetEvent($projectWorkerTimesheet->id, 'timesheet', 'approve'));
				}
			);

			$mobileNotificationData = array(
				'worker_id' => $payload->worker_id,
				'message'   => 'A project supervisor approved your Time Log.',
				'type'      => 'worker',
				'link'      => '/worker/tasks?acitve=history',
			);

			$this->createMobileNotification($mobileNotificationData);

			return response()->json(['success' => 'Time Log successfully approved.'])->setStatusCode(201);
		}
		
		return response()->json(['errors' => 'Something went wrong while approving the Time Log. Please try again later.'])->setStatusCode(201);
	}

	public function disapproveInput($payload) 
	{
		$supervisor_name = $this->getCurrentUserName();

		$updateDetails = 
		[
			'requested_by'                 => $supervisor_name,
			'request_modification_message' => $payload->request_message,
			'status'                       => $payload->status,
		];

		$companyWorkerTimesheet = CompanyWorkerTimesheet::find($payload->schedule_id); 
		$projectWorkerTimesheet = ProjectWorkersTimesheet::query()
			->select(
				'project_workers_timesheet.id as id'
			) 
			->join('assigned_workers', 'assigned_workers.id', '=', 'project_workers_timesheet.project_worker_id')
			->where(
				[
					[ 'project_workers_timesheet.worker_id',  	'=', $companyWorkerTimesheet->worker_id   	], 
					[ 'project_workers_timesheet.status', 		'=', $companyWorkerTimesheet->status 	  	], 
					[ 'project_workers_timesheet.total_hours', 	'=', $companyWorkerTimesheet->total_hours 	],
					[ 'project_workers_timesheet.date', 		'=', $companyWorkerTimesheet->date		  	],
					[ 'project_workers_timesheet.rate', 		'=', $companyWorkerTimesheet->rate		  	],
					[ 'assigned_workers.project_id', 			'=', $companyWorkerTimesheet->reference_id	]
				]
			)->first(); 

		$projectWorkerTimesheet = ProjectWorkersTimesheet::find($projectWorkerTimesheet->id);

		//? event(new DeclinedTimesheetEvent($payload->params['schedule_id'],'decline'));

		if($projectWorkerTimesheet != null)
		{
			$projectWorkerTimesheet->update($updateDetails);
			$companyWorkerTimesheet->update(
				[
					'status'  						=>  $payload->status == "absent" ? "absent" : 'request modification', 
					'request_modification_message'  =>  $payload->request_message  
				]
			);

			$message = $payload->status == "absent" ? "A project supervisor set your Time Log as absent."  :  "A project supervisor is requesting to modify your Time Log.";
			
			$mobileNotificationData = array(
				'worker_id' => $payload->worker_id,
				'message'   => $message,
				'type'      => 'worker',
				'link'      => '/worker/tasks',
			);
			
			$this->createMobileNotification($mobileNotificationData);

			return response()->json(
		[
					'success' => $payload->status == "absent" ? "Time Log successfully set as absent." : "Successfully requested a modification on Time Log."
				]
			)
			->setStatusCode(201);
		}

		return response()->json(['errors' => 'Something went wrong. Please try again later.'])->setStatusCode(201);
	}

	public function getWorkerTasksByProject($project_id, $date) 
	{
		$user_id = Auth::user()->id;

		return CompanyWorkerTimesheet::select(
			'company_workers_timesheet.id',
			DB::raw("CONCAT(workers.first_name,' ',workers.last_name) AS display_name"),
			'company_workers_timesheet.total_hours',
			'company_workers_timesheet.status', 
			'company_workers_timesheet.worker_id', 
			'company_workers_timesheet.request_modification_message as message', 
			'company_workers_timesheet.date', 
			'projects.clock_in',
			'projects.clock_out',
			'projects.date_start',
			'projects.date_end',
			'projects.name as project_name',
			DB::raw("CONCAT(workers.street_address,', ',workers.city,', ',workers.state,', ',workers.zipcode) AS address")
		)
			// ->join('assigned_workers','assigned_workers.id','=','company_workers_timesheet.project_worker_id')
			->join('project_supervisors','project_supervisors.project_id', '=','company_workers_timesheet.reference_id')
			->join('projects','projects.id' ,'=','company_workers_timesheet.reference_id')
			->join('workers','workers.id','=','company_workers_timesheet.worker_id')
			->where('project_supervisors.user_id', $user_id)
			->where('project_supervisors.project_id',$project_id)
			->whereNull('project_supervisors.deleted_at')
			->where('company_workers_timesheet.date','=',$date)
			->where('company_workers_timesheet.role', '=', 'worker')
			->orderBy('total_hours', 'desc')
			->get();
	}

	public function getScheduleSummary($project_id, $date) 
	{
		$worker_hours    = $this->getWorkerTasksByProject($project_id, $date);
		$overall_status  = 'Done';
		$Pending_count   = 0;
		$Approved_count  = 0;
		$Submitted_count = 0;

		for ($x = 0; $x <= count($worker_hours) - 1; $x++) 
		{
			if (
				$worker_hours[$x]->status == 'pending' ||
				$worker_hours[$x]->status =='request modification' ||
				$worker_hours[$x]->status =='absent'
			) {
				$overall_status = 'Pending';
				$Pending_count++;
			} elseif ($worker_hours[$x]->status == 'confirmed absent' || $worker_hours[$x]->status == 'submitted') {
				$Submitted_count++;
			} elseif ($worker_hours[$x]->status == 'approved') {
				$Approved_count++;
			}
		}

		return [
			'approved_count'  => $Approved_count,
			'pending_count'   => $Pending_count,
			'submitted_count' => $Submitted_count,
			'overall_status'  => $overall_status
		];
	}

	public function GeneratePeriod($date,$project,$list) {
		$count = Carbon::parse(
			$date ? 
			$date->from :
			$this->getServerTodayDate()
		)->diffInDays(Carbon::parse(
			(
				$date  ? 
				$date->to : 
				(
					$list == 'pending' ?
					Carbon::now()->add(30, 'days') :
					Carbon::now()->subtract(30, 'days')
				)
			)
		));
		$datePreiod = CarbonPeriod::create(
			(
				$date  ? 
				$date->from : 
				(
					$list == 'pending' ?
					Carbon::parse($this->getServerTodayDate()) :
					Carbon::now()->subtract(30, 'days')
				)
			),
			(
				$date  ? 
				$date->to : 
				(
					$list == 'pending' ?
					Carbon::now()->add(30, 'days') :
					Carbon::parse($this->getServerTodayDate())
				)
			)
		);

		return [
			'count'  => $count,
			'period' => $datePreiod
		];
	}

	public function unique_multidim_array($array, $key) {
		$temp_array = array();
		$i = 0;
		$key_array = array();
	
		foreach ($array as $val) {
			if (!in_array($val[$key], $key_array)) {
				$key_array[$i] = $val[$key];
				$temp_array[$i] = $val;
			}
			$i++;
		}
		return $temp_array;
	}

	public function getPendingProjectDates($user_id) {
		$projects = ProjectWorkersTimesheet::select(
			'project_workers_timesheet.date',
			'project_workers_timesheet.status',
			'projects.name as project_name',
			'companies.name as company_name',
			'projects.location',     
			'assigned_workers.project_id',
			'assigned_workers.worker_id'
		)
			->join('assigned_workers', 'assigned_workers.id', '=', 'project_workers_timesheet.project_worker_id')
			->join('projects', 'projects.id','=', 'assigned_workers.project_id')
			->join('companies','companies.id','=','projects.company_id')
			->join('project_supervisors', 'project_supervisors.project_id', '=', 'assigned_workers.project_id')
			->where('project_supervisors.user_id', $user_id)
			->whereIn('project_workers_timesheet.status',['submitted','pending'])
			->whereDate('project_workers_timesheet.date', '<=', Carbon::now()->toDateString())
			->orderBy('date','asc')
			->get();
		return count($projects) != 0 ? $projects : null;
	}

	public function DateBetweenDates($current, $date_from, $date_to) 
	{
		return (($current->gte($date_from)) && ($current->lte($date_to)));
	}

	public function confirmedAbsent($payload){
		// validate query params
        $rules = array(
            'id' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

		$updateTimesheet = ProjectWorkersTimesheet::where('id', $payload->id)->update(['status' => 'confirmed absent']);

		if($updateTimesheet){
			return response()->json(['success' => 'Time Log successfully confirmed as absent.'])->setStatusCode(201);
		}	
		return response()->json(['errors' => 'Something went wrong. Please try again later.'])->setStatusCode(201);
	}

	public function remindWorker($payload){
		$rules = array(
            'worker_id' => 'required',
            'date' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }
        
        $message = 'Please submit a time log for the ' . Carbon::parse($payload->date)->format('jS \\of F Y') .'.';
        $mobileNotificationData = array(
            'worker_id' => $payload->worker_id,
            'message' => $message,
            'type' => 'worker',
            'link' => '/worker/tasks',
        );
        $notification = $this->createMobileNotification($mobileNotificationData); 

		if($notification){
			return response()->json(['success' => 'Reminder sent successfully.'])->setStatusCode(201);
		}	
		return response()->json(['errors' => 'Something went wrong. Please try again later.'])->setStatusCode(201);
	}
}