<?php

namespace App\Modules\Mobile\Worker;

use App\Http\Resources\Mobile\WorkerSchedules as WorkerSchedulesResource;
use App\Models\AssignedWorkers;
use App\Models\Company;
use App\Models\CompanyWorkerTimesheet;
use App\Models\Projects;
use App\Models\ProjectWorkersTimesheet;
use App\Models\ProjectSupervisors;
use App\Models\Worker;
use App\Modules\Mobile\Worker as WorkerModule;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use App\Traits\UserTraits;
use Illuminate\Support\Facades\Auth;
use App\Traits\CreateMobileNotificationTraits;

class Overview
{
    use UserTraits, CreateMobileNotificationTraits;

    public function fetchOverview($payload)
    {
        $offset = $payload->offset ? $payload->offset : 0;
        $limit = $payload->limit;
        $workerId = Auth::user()->id;
        $filters = json_decode($payload->filters);

        $company = Company::companyInfo($this->getCurrentUser()->company_id);
        $period = [];

        if ($filters->isActive) 
        {
            $period = 
            [
                'from' => $filters->date->from,
                'to' => $filters->date->to,
            ];
        } 
        else 
        {
            $period = 
            [
                'from' => Carbon::now()->toDateString(),
                'to' => Carbon::now()->add('30', 'days')->toDateString(),
            ];
        }

        $schedules = ProjectWorkersTimesheet::select(
                'project_workers_timesheet.id',
                'project_workers_timesheet.total_hours',
                'project_workers_timesheet.status',
                'projects.name as project_name',
                'companies.name as company_name',
                'projects.location',
                'projects.clock_in',
                'projects.clock_out',
                'project_workers_timesheet.date',
            )
            ->join('assigned_workers', 'assigned_workers.id', '=', 'project_workers_timesheet.project_worker_id')
            ->join('projects', 'assigned_workers.project_id', '=', 'projects.id')
            ->join('companies', 'companies.id', '=', 'projects.company_id')
            ->where('project_workers_timesheet.worker_id', $workerId)
            ->whereBetween('project_workers_timesheet.date', [$period['from'], $period['to']])
            ->whereNull('project_workers_timesheet.deleted_at')
            ->orderBy('date', 'ASC');

        $data = $schedules->get();
        $arrayData = $this->toDataArray($data);

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

        foreach ($dateOptions['period'] as $key => $date) 
        {
            $needle = array_search(Carbon::parse($date)->toDateString(), array_column($arrayData, 'date'));
            $borrowerData = WorkerModule::getBorrowerCompany($workerId, Carbon::parse($date)->toDateString());

            if ($key >= $offset && $key <= $limit - 1) 
            {
                if ($needle === false) 
                {
                    if ($borrowerData) 
                    {
                        array_push($hits, [
                            "id" => rand(10, 1000),
                            "company_name" => $borrowerData->name,
                            "project_name" => 'Stand by',
                            "status" => 'Stand by',
                            "clock_in" => null,
                            "clock_out" => null,
                            "date" => Carbon::parse($date)->toDateString(),
                            "address" => 'Unavailable',
                            "location" => [
                                "street_address" => $borrowerData->street_address,
                                "city" => $borrowerData->city,
                                "state" => $borrowerData->state,
                                "zipcode" => (int) $borrowerData->zipcode,
                                "report_to" => $borrowerData->contact_person_name,
                                "tel_no" => $borrowerData->company_tel,
                            ],
                            "total_hours" => 00.0,
                            "has_project" => false,
                        ]);
                    } else {
                        array_push($hits, [
                            "id" => rand(10, 1000),
                            "company_name" => $company->name,
                            "project_name" => 'Stand By',
                            "status" => 'Stand By',
                            "clock_in" => null,
                            "clock_out" => null,
                            "date" => Carbon::parse($date)->toDateString(),
                            "address" => 'Unavailable',
                            "location" => [
                                "street_address" => $company->street_address,
                                "city" => $company->city,
                                "state" => $company->state,
                                "zipcode" => (int) $company->zipcode,
                            ],
                            "total_hours" => 00.0,
                        ]);
                    }
                } 
                else 
                {
                    //! Update company details to borrower's
                    if ($borrowerData) 
                    {
                        $arrayData[$needle]['address'] = $borrowerData->street_address;
                        $arrayData[$needle]['address'] .= ', ' . $borrowerData->city;
                        $arrayData[$needle]['address'] .= ', ' . $borrowerData->state;
                        $arrayData[$needle]['address'] .= ', ' . $borrowerData->zipcode;
                    }

                    array_push($hits, $arrayData[$needle]);
                }
            }
        }

        return [
            "count" => count($data),
            "hits" => $hits,
            "Actual_Timesheet" => $arrayData,
            "generated_period" => $dateOptions['period'],
        ];
    }

    public function getSchedule($payload)
    {
        $workerId = Auth::user()->id;
        $borrowerData = WorkerModule::getBorrowerCompany($workerId, $this->getServerTodayDate());

        $collection = WorkerSchedulesResource::collection(
            ProjectWorkersTimesheet::select(
                'project_workers_timesheet.id',
                'project_workers_timesheet.status',
                'project_workers_timesheet.time_in as clock_in',
                'project_workers_timesheet.time_out as clock_out',
                'project_workers_timesheet.total_hours',
                'project_workers_timesheet.date',
                'project_workers_timesheet.request_modification_message as message',
                'projects.name as project_name',
                'projects.location',
                'projects.worker_items',
                'projects.additional_info',
                'companies.name as company_name',
            )
                ->join('assigned_workers', 'assigned_workers.id', '=', 'project_workers_timesheet.project_worker_id')
                ->join('projects', 'assigned_workers.project_id', '=', 'projects.id')
                ->join('companies', 'companies.id', '=', 'projects.company_id')
                ->where('project_workers_timesheet.id', $payload->schedule_id)
                ->get()
        )->resolve();

        // Update company details to borrower's
        if ($borrowerData) {
            $collection[0]['project_address'] = $borrowerData->street_address;
            $collection[0]['project_address'] .= ', ' . $borrowerData->city;
            $collection[0]['project_address'] .= ', ' . $borrowerData->state;
            $collection[0]['project_address'] .= ', ' . $borrowerData->zipcode;
        }

        return $collection;
    }

    public function saveRenderedHours($payload)
    {
        $workerId = Auth::user()->id;
        
        $data = $this->fetchWorkerProjectTimesheetData($payload->schedule_id);
        $projectID = $data->project_id;

        $saveCompanyWorkerTimesheetTransaction = null;
        $saveProjectWorkerTimesheetTransaction = null;

        switch ($data->worker_type) 
        {
            case 'inhouse':
                $params = 
                [
                    'rendered_hours' => $payload->rendered_hours,
                    'date' => $data->date,
                    'rate' => $data->rate,
                ];

                $saveCompanyWorkerTimesheetTransaction = $this->saveCompanyWorkerTimesheet($workerId, $params, $data->company_id, $workerId);
                $saveProjectWorkerTimesheetTransaction = $this->SaveProjectWorkerTimesheet($payload);
                break;

            case 'borrowed':
                $saveProjectWorkerTimesheetTransaction = $this->SaveProjectWorkerTimesheet($payload); //project time sheet table
                break;
        }

        if($saveProjectWorkerTimesheetTransaction)
        {
            // Supervisor notification
            $workerFullName = Auth::user()->first_name ." ". Auth::user()->last_name;
            $projectSupervisors = $this->fetchProjectSupervisor($projectID); // fetch project supervisor
            
            foreach($projectSupervisors as $supervisor){
                $mobileNotificationData = array(
                    'worker_id' => $supervisor->user_id,
                    'message' => ucfirst($workerFullName) .' submitted a Time Log.',
                    'type' => 'user',
                    // 'link' => '/company/supervisor/tasks',
                    'link' => '/company/supervisor/tasks/view-attendance?date='. Carbon::parse($data->date)->format('Y-m-d') .'&sid=' . $projectID,
                );
                $this->createMobileNotification($mobileNotificationData);
            }
        }

        $result = null;

        if ($data->worker_type == 'inhouse') 
        {
            $result = 
            [
                'success' => $saveCompanyWorkerTimesheetTransaction && $saveProjectWorkerTimesheetTransaction,
                'worker_type' => $data->worker_type,
            ];
        } 
        else 
        {
            $result = [
                'success' => $saveProjectWorkerTimesheetTransaction,
                'worker_type' => $data->worker_type,
            ];
        }

        return $result;
    }

    public function fetchWorkerProjectTimesheetData($scheduleID)
    {
        return ProjectWorkersTimesheet::select(
            'project_workers_timesheet.*',
            'projects.company_id',
            'projects.id as project_id',
        )
            ->join('assigned_workers', 'project_workers_timesheet.project_worker_id', 'assigned_workers.id')
            ->join('projects', 'projects.id', 'assigned_workers.project_id')
            ->where('project_workers_timesheet.id', $scheduleID)->first();
    }

    public function toDataArray($data)
    {
        $arr = [];
        for ($x = 0; $x <= count($data) - 1; $x++) 
        {
            array_push($arr, 
                [
                    "clock_in"     => $data[$x]->clock_in,
                    "clock_out"    => $data[$x]->clock_out,
                    "company_name" => $data[$x]->company_name,
                    "date"         => $data[$x]->date,
                    "id"           => $data[$x]->id,
                    "location"     => json_decode($data[$x]->location),
                    "project_name" => $data[$x]->project_name,
                    "status"       => $data[$x]->status,
                    "total_hours"  => $data[$x]->total_hours,
                ]
            );
        }

        return $arr;
    }

    public function GeneratePeriod($date, $caller)
    {
        $from = null;
        $to = null;

        if ($caller == 'pending') 
        {
            $from = Carbon::now();
            $to = Carbon::now()->add(30, 'days');
        } 
        else 
        {
            $from = Carbon::now()->subtract(30, 'days');
            $to = Carbon::now();
        }

        $count = Carbon::parse($date ? $date->from : $from)
            ->diffInDays(Carbon::parse($date ? $date->to : $to));

        $datePreiod = CarbonPeriod::create($date ? $date->from : $from, $date ? $date->to : $to);

        return [
            'count' => $count,
            'period' => $datePreiod->toArray(),
        ];
    }

    public function saveCompanyWorkerTimesheet($workerId, $payload, $company, $project_worker_id)
    {
        $projectId = AssignedWorkers::join('assigned_availability', 'assigned_availability.assigned_worker_id', '=', 'assigned_workers.id')
            ->where('assigned_workers.worker_id', $project_worker_id)
            ->first()->project_id;

        $projectName = Projects::select('name')->where('id', $projectId)->first()->name;

        $data = array(
            'worker_id'    => $workerId,
            'company_id'   => $company,
            'date'         => Carbon::parse($payload['date']),
            'reference_id' => $projectId,
            'rate'         => $payload['rate'],
            'description'  => "Hours rendered for project " . $projectName . " as worker",
            'status'       => 'submitted',
            'time_in'      => '00:00',
            'time_out'     => '00:00',
            'total_hours'  => $payload['rendered_hours'],
            'type'         => 'project',
            'role'         => 'worker',
        );

        $companyWorkerTimesheet = CompanyWorkerTimesheet::query() 
            ->where(
                [
                    [ 'worker_id',      '=', $workerId              ],
                    [ 'reference_id',   '=', $data['reference_id']  ],
                    [ 'date',           '=', $data['date']          ], 
                    [ 'type',           '=', $data['type']          ], 
                    [ 'role',           '=', $data['role']          ],  
                ]
            )
            ->whereIn('status', ['request modification', 'absent'])
            ->first();
            
        if ($companyWorkerTimesheet == null)
        {
            return CompanyWorkerTimesheet::create($data);
        }
        
        return $companyWorkerTimesheet->update(
            [
                'total_hours' => $data['total_hours'], 
                'status'      => 'submitted'
            ]
        );

    }

    public function SaveProjectWorkerTimesheet($data)
    {
        $updateDetails = [
            'total_hours' => $data->rendered_hours,
            'status' => 'submitted',
        ];

        return ProjectWorkersTimesheet::where('id', $data->schedule_id)->update($updateDetails);
    }

    public function fetchProjectSupervisor($projectID)
    {
        return ProjectSupervisors::where('project_id', $projectID)
            ->whereRaw('project_supervisors.date_to >= CURDATE()')
            ->get();
    }
}
