<?php

namespace App\Modules\Company\Users;

use App\Models\Worker;
use App\Models\WorkerExperience;
use App\Models\CompanyBurdenRate;
use App\Models\CompanyExperience;
use App\Models\Availabilities;
use App\Models\WorkAreaLists;

use Intervention\Image\Facades\Image;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Carbon\Carbon;

use App\Traits\MobileNumberValidatorTraits;
use App\Traits\ValidatorTraits;
use App\Traits\ZipcodeTraits;

use App\Events\Company\CreateSearchDataForInvitedWorkerEvent;

class Invitation
{
    use ValidatorTraits, MobileNumberValidatorTraits, ZipcodeTraits;

    public function acceptInvitation($payload){

        $email_address = $payload->email_address;
        
        /*========================================================================================================
        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',
            'expertise' => 'required',
            'level_of_experience' => 'required',
            'company_id' => 'required',
            'willing_distance' => 'required',
        );

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

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

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

        // Check if already has a worker-data
        $oldWorkerData = $this->checkWorker($email_address);
        if (!$oldWorkerData) {
            return response()->json(['errors' => ["Sorry, worker doesn't exist."]])->setStatusCode(201);
        }

        DB::beginTransaction();

        $first_name = ucfirst($payload->first_name);
        $last_name = ucfirst($payload->last_name);
        $profile_picture = $payload->profile_picture;
        $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;
        $password = Hash::make($payload->password);
        $company_id = $oldWorkerData->company_id;
        $willingDistance = $payload->willing_distance;


        /*========================================================================================================
        Profile picture
        ========================================================================================================*/
        if ($profile_picture != '') {
            $image_64 = $profile_picture;
            $extension = explode('/', explode(':', substr($image_64, 0, strpos($image_64, ';')))[1])[1]; // .jpg .png
            $replace = substr($image_64, 0, strpos($image_64, ',') + 1);
            // find substring fro replace here eg: data:image/png;base64,
            $image = str_replace($replace, '', $image_64);
            $image = str_replace(' ', '+', $image);
            $imageName = Str::random(10) . '.' . $extension;
            // resize image
            $photo = Image::make(base64_decode($image))
                ->resize(120, 120)
                ->encode($extension, 90);
            $profile_picture = 'data:image/' . $extension . ';base64,' . base64_encode($photo);
        }


        /*========================================================================================================
        Prepare data and create User
        ========================================================================================================*/
        $user_data = [
            'first_name' => $first_name,
            'last_name' => $last_name,
            'password' => $password,
            'email_address' => $email_address,
            'email_verified_at' => Carbon::now(),
            'profile_picture' => $profile_picture,
            'is_active' => 'true',
            'enable_2fa' => 'false',
            'phone_num' => $phone_num,
            'email_verification_code' => null,
            'is_account_disabled' => 'false',
            'street_address' => $street_address,
            'city' => $city,
            'state' => $state,
            'zipcode' => $zipcode,
            'additional_details' => $additional_details,
            'distance' => $willingDistance,
        ];

        $workerData = tap(Worker::where('email_address', $email_address))->update($user_data)->first();

        /*========================================================================================================
        worker experiences data
        ========================================================================================================*/
        $expertise = $payload->expertise;
        $level_of_experience = $payload->level_of_experience;
        $worker_type = 'worker';

        /*========================================================================================================
        worker areas of work data
        ========================================================================================================*/
        $areas_of_work = $payload->areas_of_work;

        /*========================================================================================================
        preparing worker experiences data to be saved on database
        ========================================================================================================*/

        // 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';
        }


        /*========================================================================================================
            worker areas
        ========================================================================================================*/
        // remove worker work areas if has one
        $this->removeWorkerWorkAreaList($workerData->id);

        if (is_array($areas_of_work) || is_object($areas_of_work)) {
            foreach ($areas_of_work as $area_of_work) {
                $worker_areas_of_work_data = array(
                    'work_area_id' => $area_of_work,
                    'worker_id' => $workerData->id,
                    'worker_type' => $worker_type,
                );
                $workerWorkAreaListTransaction = WorkAreaLists::create($worker_areas_of_work_data);
            }
        } else {
            return $areas_of_work;
        }


        /*========================================================================================================
        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' => $workerData->id,
            'company_id' => $company_id,
            'worker_type' => 'inhouse',
            'rate' => $workerData->flat_rate,
            'min_availability_date' => $min_availability_date,
            'max_availability_date' => $max_availability_date,
        );
        $workerAvailabilityTransaction = $this->saveWorkerAvailability($worker_availability_data);

        /*========================================================================================================
        If there's an error or queries don't do their job, rollback!
        ========================================================================================================*/
        if (!$workerWorkAreaListTransaction && !$workerAvailabilityTransaction && !$workerExperienceTransaction) {
            DB::rollBack();
            return response()->json(
                ['error' => 'Server error.',
                    'company_work_area_list_result' => $workerWorkAreaListTransaction,
                    'workerAvailabilityTransaction' => $workerAvailabilityTransaction,
                    'workerExperienceTransaction' => $workerExperienceTransaction,
                    'test' => $test,
                ]);

        } else {
            event(new CreateSearchDataForInvitedWorkerEvent($workerData->id)); //Event for creating search data on newly accepted worker
            DB::commit();
            return response()->json(['success' => true, 'message' => 'Data updated successfully.' , 'test' => $test])->setStatusCode(201);
        }
    }

    public function checkWorker($email_address)
    {
        return Worker::select(
            'company_users.company_id', 
            'workers.id'
        )
        ->join('company_users', 'company_users.worker_id', 'workers.id')
        ->where('workers.email_address', $email_address)
        ->first();
    }

    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 addWorkerExperience($data){
        return WorkerExperience::create($data);
    }

    public function getCompanyExperience($experienceID, $companyID){
        return CompanyExperience::where('id', $experienceID)->where('company_id', $companyID)->first();
    }

    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 removeWorkerWorkAreaList($workerID){
        return WorkAreaLists::where('worker_id', $workerID)
            ->where('work_area_lists.worker_type', 'worker')
            ->delete();
    }

    public function saveWorkerAvailability($worker_availability_data)
    {
        return Availabilities::create($worker_availability_data);
    }

}