<?php

namespace App\Modules\Company\Whiteboard\Project;

use App\Events\Company\UpdateDateOfProjectWorkerTimeSheetEvent;
use App\Models\Projects;
use App\Models\ProjectSupervisors;
use App\Traits\CreateUserActionTraits;
use App\Traits\UserTraits;
use App\Traits\ValidatorTraits;
use App\Traits\CreateMobileNotificationTraits;
use Illuminate\Support\Facades\DB;

class UpdateProject
{
    use CreateUserActionTraits, UserTraits, ValidatorTraits, CreateMobileNotificationTraits;

    public function update($payload, $id)
    {
        DB::beginTransaction();
        $projectId = $id;
        $companyId = $this->getCurrentUser()->company_id;
        $projectName = $payload->project_name;
        $projectManager = $payload->project_manager;
        $supervisors = $payload->supervisors;
        $startDate = $payload->start_date;
        $endDate = $payload->end_date;
        $clockIn = $payload->clock_in;
        $clockOut = $payload->clock_out;
        $description = $payload->description;
        $additionalInfo = $payload->additional_info;
        $workerItems = $payload->worker_items;
        $locationStreetAddress = $payload->location_street_address;
        $locationCity = $payload->location_city;
        $locationState = $payload->location_state;
        $locationZipcode = $payload->location_zipcode;

        // Validate Query Param
        $rules = array(
            'project_name' => 'required|max:150',
            'project_manager' => 'required',
            'supervisors' => 'required',
            'start_date' => 'required',
            'end_date' => 'required',
            'clock_in' => 'required',
            'clock_out' => 'required',
            'description' => 'required',
            'location_street_address' => 'required',
            'location_city' => 'required',
            'location_state' => 'required',
            'location_zipcode' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        // project original data
        $projectOriginalData = Projects::where('id', $projectId)->first();

        // Convert location to json array
        $location = array(
            'street_address' => $locationStreetAddress,
            'city' => $locationCity,
            'state' => $locationState,
            'zipcode' => $locationZipcode,
        );

        // preparing project data to be saved on database
        $projectData = array(
            'project_manager_id' => $projectManager,
            'name' => $projectName,
            'description' => $description,
            'additional_info' => $additionalInfo,
            'date_start' => date('Y-m-d', strtotime($startDate)),
            'date_end' => date('Y-m-d', strtotime($endDate)),
            'clock_in' => date('H:i:s', strtotime($clockIn)),
            'clock_out' => date('H:i:s', strtotime($clockOut)),
            'worker_items' => json_encode($workerItems),
            'location' => json_encode($location),
        );

        // update project data in projects table
        $projectTransaction = Projects::where('id', $projectId)
            ->where('company_id', $companyId)
            ->update($projectData);

        // delete current supervisor on project
        $oldProjectSupervisor = ProjectSupervisors::where('project_id', $projectId)->get();
        $projectSupervisorDeletionTransaction = ProjectSupervisors::where('project_id', $projectId)->delete();

        foreach ($supervisors as $supervisor) {
            // preparing project supervisor data to be saved on database
            $startDate = $supervisor['duration'][0];
            $endDate = $supervisor['duration'][1];
            $project_supervisor_data = array(
                'user_id' => $supervisor['supervisor'],
                'project_id' => $projectId,
                'date_from' => date('Y-m-d', strtotime($startDate)),
                'date_to' => date('Y-m-d', strtotime($endDate)),
            );

            // update supervisor data in project_supervisors table
            $projectSupervisorTransaction = ProjectSupervisors::create($project_supervisor_data);
        }

        // add a user action logs
        $saveUserAction = 1;
        if ($projectOriginalData->name != $projectName ||
            $projectOriginalData->project_manager_id != $projectManager ||
            $projectOriginalData->date_start != date('Y-m-d', strtotime($startDate)) ||
            $projectOriginalData->date_end != date('Y-m-d', strtotime($endDate)) ||
            $projectOriginalData->clock_in != date('H:i:s', strtotime($clockIn)) ||
            $projectOriginalData->clock_out != date('H:i:s', strtotime($clockOut)) ||
            $projectOriginalData->description != $description ||
            $projectOriginalData->additional_info != $additionalInfo ||
            $projectOriginalData->worker_items != json_encode($workerItems) ||
            $projectOriginalData->location != json_encode($location)) {
            $saveUser = $this->createUserAction('Updated the project ' . $projectName);
            if (!$saveUser) {
                $saveUserAction = 0;
            }
        }

        // update worker timesheet clock_in and clock_out
        if ($projectOriginalData->clock_in != date('H:i:s', strtotime($clockIn)) ||
            $projectOriginalData->clock_out != date('H:i:s', strtotime($clockOut))) {
            event(new UpdateDateOfProjectWorkerTimeSheetEvent($projectId, $clockIn, $clockOut));
        }

        // If there's an error or queries don't do their job, rollback!
        if (!$projectTransaction ||
            !$projectSupervisorDeletionTransaction ||
            !$projectSupervisorTransaction ||
            !$saveUserAction) {
            DB::rollBack();
            return response()->json(['error' => 'Server error.']);
        } else {
            $this->createProjectManagerMobileNotification($projectManager, $projectOriginalData->project_manager_id, $projectName, $startDate, $endDate);
            $this->createSupervisorMobileNotification($supervisors, $oldProjectSupervisor, $projectName);
            DB::commit();
            return response()->json(['success' => 'Data updated successfully.'])->setStatusCode(201);
        }
    }

    public function updateDetails($payload, $id)
    {
        DB::beginTransaction();
        $projectId = $id;
        $companyId = $this->getCurrentUser()->company_id;
        $projectName = $payload->project_name;
        $projectManager = $payload->project_manager;
        $startDate = $payload->start_date;
        $endDate = $payload->end_date;
        $locationStreetAddress = $payload->location_street_address;
        $locationCity = $payload->location_city;
        $locationState = $payload->location_state;
        $locationZipcode = $payload->location_zipcode;

        // Validate Query Param
        $rules = array(
            'project_name' => 'required|max:150',
            'project_manager' => 'required',
            'start_date' => 'required',
            'end_date' => 'required',
            'location_street_address' => 'required',
            'location_city' => 'required',
            'location_state' => 'required',
            'location_zipcode' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        // project original data
        $projectOriginalData = Projects::find($projectId);

        // Convert location to json array
        $location = array(
            'street_address' => $locationStreetAddress,
            'city' => $locationCity,
            'state' => $locationState,
            'zipcode' => $locationZipcode,
        );

        // preparing project data to be saved on database
        $projectData = array(
            'project_manager_id' => $projectManager,
            'name' => $projectName,
            'date_start' => date('Y-m-d', strtotime($startDate)),
            'date_end' => date('Y-m-d', strtotime($endDate)),
            'location' => json_encode($location),
        );

        // update project data in projects table
        $projectTransaction = Projects::where('id', $projectId)
            ->where('company_id', $companyId)
            ->update($projectData);

        // add a user action logs
        $saveUserAction = 1;
        if ($projectOriginalData->name != $projectName ||
            $projectOriginalData->project_manager_id != $projectManager ||
            $projectOriginalData->date_start != date('Y-m-d', strtotime($startDate)) ||
            $projectOriginalData->date_end != date('Y-m-d', strtotime($endDate)) ||
            $projectOriginalData->location != json_encode($location)) {

            $saveUser = $this->createUserAction("Update the project details of " . $projectName);
            if (!$saveUser) {
                $saveUserAction = 0;
            }
        }

        // If there's an error or queries don't do their job, rollback!
        if (!$projectTransaction ||
            !$saveUserAction) {
            DB::rollBack();
            return response()->json(['error' => 'Server error.']);
        } else {
             // PWA NOTIFICATIONS
             $this->createProjectManagerMobileNotification($projectManager, $projectOriginalData->project_manager_id, $projectName, $startDate, $endDate);

            DB::commit();
            return response()->json(['success' => 'Data updated successfully.'])->setStatusCode(201);
        }
    }

    public function updateAdditionalDetails($payload, $id)
    {
        DB::beginTransaction();
        $projectId = $id;
        $companyId = $this->getCurrentUser()->company_id;
        $projectName = $payload->project_name;
        $clockIn = $payload->clock_in;
        $clockOut = $payload->clock_out;
        $description = $payload->description;
        $additionalInfo = $payload->additional_info;
        $workerItems = $payload->worker_items;

        // Validate Query Param
        $rules = array(
            'project_name' => 'required',
            'clock_in' => 'required',
            'clock_out' => 'required',
            'description' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        // project original data
        $projectOriginalData = Projects::find($projectId);

        // preparing project data to be saved on database
        $projectData = array(
            'description' => $description,
            'additional_info' => $additionalInfo,
            'clock_in' => date('H:i:s', strtotime($clockIn)),
            'clock_out' => date('H:i:s', strtotime($clockOut)),
            'worker_items' => json_encode($workerItems),
        );

        // update project data in projects table
        $projectTransaction = Projects::where('id', $projectId)
            ->where('company_id', $companyId)
            ->update($projectData);

        // add a user action logs
        $saveUserAction = 1;
        if ($projectOriginalData->clock_in != date('H:i:s', strtotime($clockIn)) ||
            $projectOriginalData->clock_out != date('H:i:s', strtotime($clockOut)) ||
            $projectOriginalData->description != $description ||
            $projectOriginalData->additional_info != $additionalInfo ||
            $projectOriginalData->worker_items != json_encode($workerItems)) {

            $saveUser = $this->createUserAction('Updated the project additional details of ' . $projectName . '.');
            if (!$saveUser) {
                $saveUserAction = 0;
            }
        }

        // update worker timesheet clock_in and clock_out
        if ($projectOriginalData->clock_in != date('H:i:s', strtotime($clockIn)) ||
            $projectOriginalData->clock_out != date('H:i:s', strtotime($clockOut))) {
            event(new UpdateDateOfProjectWorkerTimeSheetEvent($projectId, $clockIn, $clockOut));
        }

        // If there's an error or queries don't do their job, rollback!
        if (!$projectTransaction ||
            !$saveUserAction) {
            DB::rollBack();
            return response()->json(['error' => 'Server error.']);
        } else {
            DB::commit();
            return response()->json(['success' => 'Data updated successfully.'])->setStatusCode(201);
        }
    }


    public function createProjectManagerMobileNotification($projectManager, $oldProjectManager, $projectName, $startDate, $endDate){
        if($projectManager != $oldProjectManager){ //for managers
            //newly added manager
            $mobileNotificationData = array(
                'worker_id' => $projectManager,
                'message' => 'You have been added as Project Manager of the project named  '. ucfirst($projectName) . " with project duration date of " . date('Y-m-d', strtotime($startDate)) . " to " . date('Y-m-d', strtotime($endDate)) . ".",
                'type' => 'user',
                'link' => '/company/manager/timelogs/submit',
            );
            $this->createMobileNotification($mobileNotificationData);

            //removed manager
            $mobileNotificationData = array(
                'worker_id' => $oldProjectManager,
                'message' => 'You have been removed as Project Manager from '. ucfirst($projectName) . ".",
                'type' => 'user',
                'link' => '/company/manager/timelogs/submit',
            );
            $this->createMobileNotification($mobileNotificationData);
        }
        return true;
    }

    public function createSupervisorMobileNotification($supervisors, $oldSupervisors, $projectName){

         // For newly added : SUPERVISOR PWA NOTIFICATION
         foreach ($supervisors as $supervisor) {
            if(!$this->isOldSupervisor($oldSupervisors, $supervisor['supervisor'])){ //if exist as old supervisor no need for notification
                $startDate = $supervisor['duration'][0];
                $endDate = $supervisor['duration'][1];
                $mobileNotificationData = array(
                    'worker_id' => $supervisor['supervisor'],
                    'message' => 'You have been added as Project Supervisor of the project named '. ucfirst($projectName) . " with project duration date of " . date('Y-m-d', strtotime($startDate)) . " to " . date('Y-m-d', strtotime($endDate)) . ".",
                    'type' => 'user',
                    'link' => '/worker/tasks',
                );
                $this->createMobileNotification($mobileNotificationData);
            }
        }

        // For removed old supervisor
        foreach ($oldSupervisors as $supervisor) {
            if(!$this->isNewSupervisor($supervisors, $supervisor->user_id)){ //if exist no need for notification
                $mobileNotificationData = array(
                    'worker_id' => $supervisor->user_id,
                    'message' => 'You have been removed as Project Supervisor from '. ucfirst($projectName) . ".",
                    'type' => 'user',
                    'link' => '/worker/tasks',
                );
                $this->createMobileNotification($mobileNotificationData);
            }
        }
    }

    public function isOldSupervisor($oldSupervisors, $newSupervisorID){
        foreach ($oldSupervisors as $supervisor) {
            if($supervisor->user_id == $newSupervisorID){
                return true;
            }
        }
        return false;
    }

    public function isNewSupervisor($newSupervisors, $oldSupervisorID){
        foreach ($newSupervisors as $supervisor) {
            if($supervisor['supervisor'] == $oldSupervisorID){
                return true;
            }
        }
        return false;
    }

}
