<?php

namespace App\Modules\Company\Users\Invitation;
use Illuminate\Support\Facades\Hash;
use App\Traits\MobileNumberValidatorTraits;
use App\Traits\GenerateAndValidateWorkerID;
use App\Traits\ValidatorTraits;
use App\Traits\ZipcodeTraits;
use App\Models\Worker;
use App\Models\WorkerExperience;
use App\Models\WorkAreaLists;
use App\Models\Availabilities;
use App\Models\CompanyUser;
use App\Models\CompanyBurdenRate;
use App\Models\WorkerInvitation;
use App\Models\CompanyExperience;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Events\Company\CreateSearchDataForInvitedWorkerEvent;

class IndividualInvitation{
    use MobileNumberValidatorTraits, GenerateAndValidateWorkerID, ValidatorTraits, ZipcodeTraits;

    public function acceptInvitation($payload){

        DB::beginTransaction();
        /*****************
         * Validations
         */
        $validate = $this->validatePhoneNumber($payload->phone_num);
        if ($validate) {
            return $validate;
        }

        $token = $payload->token;

        $workerData = Worker::where('email_verification_code', $token)->first();
        if(!$workerData){
            return response()->json(['errors' => ["Sorry, token doesn't exist."]])->setStatusCode(201);
        }

        /*========================================================================================================
        Validate Query Params
        ========================================================================================================*/
        $rules = array(
            'first_name' => 'required|max:50',
            'last_name' => 'required|max:50',
            'email_address' => 'required|max:191',
            'phone_num' => 'required|max:50',
            'street_address' => 'required|max:50',
            'city' => 'required|max:50',
            'state' => 'required|max:50',
            'zipcode' => 'required|string|min:5|max:5',
            'rate' => 'required|max:10',
            'expertise' => 'required',
            'level_of_experience' => 'required',
            'company_id' => 'required',
            'willing_distance' => 'required',
        );

        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        $validate = $this->validateZipcodeIfExisting($payload->zipcode);
        if ($validate) {
            return $validate;
        }

        /*======================================================================================================== 
            Prepare data 
        ========================================================================================================*/
        $first_name = ucfirst($payload->first_name);
        $last_name = ucfirst($payload->last_name);
        $profile_picture = $payload->profile_picture;
        $email_address = $payload->email_address;
        $phone_num = '+1' . str_replace( array('-', '(', ')', ' ' ), '', $payload->phone_num);
        $street_address = $payload->street_address;
        $city = $payload->city;
        $state = $payload->state;
        $zipcode = $payload->zipcode;
        $additional_details = $payload->additional_details;
        $hourly_rate = $payload->rate;
        $date_hired = now();
        $company_id = $payload->company_id;
        $availability_status = 'reserved';
        $emailVerificationCode = $payload->invitation_code;
        $password = Hash::make($payload->password);
        $expertise = $payload->expertise;
        $level_of_experience = $payload->level_of_experience;
        $worker_type = 'worker';
        $areas_of_work = $payload->areas_of_work;   
        $other_experience = $payload->other_experience;
        $other_expertise = $payload->other_expertise;
        $willingDistance = $payload->willing_distance;


        /*======================================================================================================== 
            Prepare worker/user data and create User
        ========================================================================================================*/
        $worker =  array (
            'first_name'                => $first_name ,
            'last_name'                 => $last_name ,
            'password'                  => $password ,
            'email_verified_at'         => now(),
            'profile_picture'           => $profile_picture ,
            'is_active'                 => 'true' ,
            'enable_2fa'                => 'false' ,
            'phone_num'                 => $phone_num,
            'rate'                      => $hourly_rate ,
            'date_hired'                => $date_hired , 
            'is_account_disabled'       => 'false',
            'street_address'            => $street_address ,
            'city'                      => $city,
            'state'                     => $state ,
            'zipcode'                   => $zipcode ,
            'additional_details'        => $additional_details,
            'email_verification_code'        => null,
            'distance' => $willingDistance,
        );

        $workerTransaction = $this->updateWorker($email_address, $worker);

        /*======================================================================================================== 
            Prepare worker_experiences data and create
        ========================================================================================================*/

        // check worker experience if has one
        $workerExperienceData = $this->checkWorkerExperience($workerData->id);

        $test = true;
        if($workerExperienceData && !($level_of_experience == $workerExperienceData->experience_id)){
            //different epxerience meaning change the worker experience
            $newCompanyExperienceBurdenRateData = $this->getCompanyBurdenRateData($level_of_experience);

            $newWorkerExperienceData = array(
                'experience_id' => $level_of_experience,
                'expertise_id' => $expertise,
                'is_worker' => 'true',
                'experience' => $payload->other_experience,
                'expertise' => $payload->other_expertise,
                'burden_rate_id' => $newCompanyExperienceBurdenRateData->id
            );

            $workerExperienceTransaction = $this->updateWorkerExperience($workerData->id, $newWorkerExperienceData);
            $test = 'update the Experience';

        }else if($workerExperienceData && ($level_of_experience == $workerExperienceData->experience_id)){
            //has experience data, but no changes
            $workerExperienceTransaction = true;
            $test = 'notUpdating the experience';

        }else{
            //no expereience data
            $companyExperienceAndBurdenData = $this->getCompanyExperienceAndBurdenDataUsingId($level_of_experience, $company_id);

            $newWorkerExperienceData = array(
                'worker_id' => $workerData->id,
                'experience_id' => $level_of_experience,
                'expertise_id' => $expertise,
                'is_worker' => 'true',
                'experience' => $payload->other_experience,
                'expertise' => $payload->other_expertise,
                'burden_rate_id' => $companyExperienceAndBurdenData->company_burden_rate_id,
            );
            
            $workerExperienceTransaction = $this->addWorkerExperience($newWorkerExperienceData);
            $test = 'crete new worker experience';
        }


        /*======================================================================================================== 
            Create Areas of work
        ========================================================================================================*/
        
        $areas_of_work = $this->save_areasof_work($areas_of_work, $workerTransaction->id);

        /*======================================================================================================== 
            Get the worker company id
        ========================================================================================================*/

        $company_id = $this->getCompanyId($workerTransaction->id);

        /*======================================================================================================== 
            preparing worker availability data to be saved on database
        ========================================================================================================*/
        $min_availability_date = date("Y-m-d");
        $max_availability_date = date('Y-m-d', strtotime('+10 years'));
        $worker_availability_data = array(
            'worker_id' => $workerTransaction->id,
            'company_id' => $company_id,
            'worker_type' => 'inhouse',
            'rate' =>  $hourly_rate,
            'min_availability_date' => $min_availability_date,
            'max_availability_date' => $max_availability_date,
        );

        $availabilityTransaction = $this->saveWorkerAvailability($worker_availability_data);

        // $removeInvitation = $this->removeInvitation($email_address);

       if ( !$availabilityTransaction || !$areas_of_work || !$workerExperienceTransaction || !$workerTransaction)
        {
            DB::rollBack();
            return response()->json(
                ['error' => 'Server error.',
                    'workerTransaction' => $workerTransaction,
                    'workerExperienceTransaction' => $workerExperienceTransaction,
                    'areas_of_work' => $areas_of_work,
                    'availabilityTransaction' => $availabilityTransaction,
                    'test' > $test,
                ]);
        } else {
            event(new CreateSearchDataForInvitedWorkerEvent($workerData->id)); //Event for creating search data on newly accepted worker
            DB::commit();
            return response()->json(['success'=> 'User Information updated successfully.'])->setStatusCode(201);
        }
    }

    public function updateWorker($email_address, $data){
        return tap(Worker::where('email_address', $email_address))->update($data)->first();
    }

    public function createWorkerExperience($data){
        return WorkerExperience::create($data);
    }

    public function save_areasof_work($areas, $worker_id){

        $areas_to_num = [];
        //save multiple entry base on the size of areas
        foreach ($areas as $area) {
            WorkAreaLists::insert(['work_area_id' => $area, 'worker_id' => $worker_id, 'worker_type' => 'worker']); 
            array_push($areas_to_num, $area); 
        }
        return $areas_to_num;
    }
    
    public function saveWorkerAvailability($worker_availability_data)
    {
        return Availabilities::create($worker_availability_data);
    }
    
    public function removeInvitation($email_address){
        return WorkerInvitation::where('email_address', $email_address)->delete();
    }

    public function getCompanyId($id){
        $data = CompanyUser::where('worker_id', $id)->first();
        return $data->company_id;
    }

    public function createBurdenRate($data){
        return CompanyBurdenRate::create($data);
    }


    public function getInvitationData($payload){
        $token = $payload->token;

        $workerData = Worker::select(
                'workers.first_name', 
                'workers.last_name', 
                'workers.email_address', 
                'workers.phone_num', 
                'workers.street_address', 
                'workers.state', 
                'workers.city', 
                'workers.zipcode', 
                'workers.rate', 
                'company_users.company_id',
                'worker_experiences.experience',
                'worker_experiences.experience_id',
                'worker_experiences.expertise as expertise',
                'worker_experiences.expertise_id',
                'expertises.name as expertise_name',
            )
            ->with('work_area_lists')
            ->where('email_verification_code', $token)
            ->join('company_users', 'company_users.worker_id', 'workers.id')
            ->leftJoin('worker_experiences', 'worker_experiences.worker_id', '=', 'workers.id')
            ->leftJoin('expertises', 'expertises.id', '=', 'worker_experiences.expertise_id')
            ->first();
       
            if($workerData){
                return [
                    'workerData' => $workerData,
                    'companyExperience' => $this->getCompanyExperience($workerData->company_id),
                ];
            }
    }

    public function getCompanyExperience($companyID){
        $companyExperiences =  CompanyExperience::where('company_id', $companyID)->get();
        //make the 'Other or Others' item, as the last item
        foreach($companyExperiences as $key => $experience){
            
            if($experience->name == 'Other' || $experience->name == 'Others'){
                $holdOther = $experience;
                unset($companyExperiences[$key]);
            }
        }
        if(!empty($holdOther)){
            $companyExperiences->push($holdOther); //set the other as the last item
        }
        return $companyExperiences;
    }

    public function checkWorkerExperience($workerID){
        return WorkerExperience::where('worker_id', $workerID)->first();
    }

    public function getCompanyBurdenRateData($experienceID){
        return CompanyBurdenRate::where('company_experience_id', $experienceID)->first();
    }

    public function updateWorkerExperience($workerID, $data){
        return WorkerExperience::where('worker_id', $workerID)->update($data);
    }

    public function getCompanyExperienceAndBurdenDataUsingId($companyExperienceID, $companyID){
        return CompanyExperience::select(
            'company_experiences.id as company_experience_id',
            'company_experiences.name',
            'company_burden_rate.company_id',
            'company_burden_rate.id as company_burden_rate_id',
        )
        ->join('company_burden_rate', 'company_burden_rate.company_experience_id', 'company_experiences.id')
        ->where('company_experiences.id', $companyExperienceID)
        ->where('company_experiences.company_id', $companyID)
        ->first();
    }

    public function addWorkerExperience($data){
        return WorkerExperience::create($data);
    }
}