<?php

namespace App\Modules\Company\Employees\Invitation;

use App\Models\Worker;
use App\Models\CompanyUser;
use App\Models\PasswordResets;
use App\Jobs\Company\ProcessSendEmailWorkerInvitation;
use App\Traits\CheckEmployeeCountAvailableTraits;
use App\Traits\CreateUserActionTraits;
use App\Traits\GenerateAndValidateWorkerID;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

class GradualInvitation
{

    use GenerateAndValidateWorkerID, CheckEmployeeCountAvailableTraits, CreateUserActionTraits;
    public $companyID;


    public function __construct()
    {
        $this->companyID = $this->getCurrentUser()->company_id;
    }

    public function invite($payload)
    {
        $data = $payload->payload;
        $company_id =  $this->companyID;

        /******************** ********************
        Validation in worker email
         */
        $rules = [
            'payload' => 'required|array',
            'payload.*.email_address' => 'required|unique:workers',
        ];

        $validator = Validator::make($payload->all(), $rules);

        if ($validator->fails()) {
            $error = $validator->errors()->first();
            $index = preg_replace('/\D/', '', $error);
            $response = $this->checkIfCompanyEmployee($data[$index]['email_address'], $company_id);
            return response()->json(['errors' => $response])->setStatusCode(200);
        }

        /* Validate maximum emp */
        $validate = $this->employeeCountValidation($company_id, count($data));
        if ($validate) {
            return $validate;
        }

        //Delete duplicate email address
        $data = $this->multi_unique($data);

        foreach ($data as $user) {
            $email_verification = $this->sendEmailInvitation($user);
        }

        /*========================================================================================================
        Added user transaction for reports
        ========================================================================================================*/
        $action = (count($data) > 1) ? " Invited an Employees" : "Invited an Employee";
        $actionTransaction = $this->createUserAction($action);

        return $email_verification;
    }

    public function sendEmailInvitation($user)
    {
        $company_id =  $this->companyID;

        DB::beginTransaction();

        $email_address = strtolower($user['email_address']);
        $token = $user['admin_verified'] ? hash('sha256', $plainTextToken = Str::random(80)) . "_admin_verified" : hash('sha256', $plainTextToken = Str::random(80));

        /*========================================================================================================
        generate new worker id
        ========================================================================================================*/
        $workerGeneratedId = $this->generateWorkerId($company_id);

        /*==================================cam======================================================================
        Validate Worker id if already existed on specific company
        ========================================================================================================*/

        $validate = $this->validateWorkerGeneratedId($company_id, $workerGeneratedId);
        if (!$validate) {
            return response()->json(['errors' => ['The worker id has already been taken.', 'worker_id' => $workerGeneratedId]])->setStatusCode(201);
        }

        /*========================================================================================================
        Prepare and Save Worker data
        ==================================================*/

        $worker_data = array(
            'worker_id' => $workerGeneratedId,
            'email_address' => $email_address,
            'first_name' => 'Temp',
            'last_name' => 'Temp',
            'password' => Hash::make(Str::random(8)),
            'zipcode' => '00000',
            'rate' => $user['hourly_rate'],
            'email_verification_code' => $token,
            'date_hired' => $user['date_hired']? Carbon::parse($user['date_hired']) : null,
        );

        $workerTransaction = $this->createWorker($worker_data);
        if (str_contains($token, 'admin_verified')) {
            PasswordResets::create([
                'email' => $email_address,
                'token' => $token,
            ]);
        }

        /*========================================================================================================
        Prepare and Save Company User
        ==================================================*/
        $company_user = array(
            'worker_id' => $workerTransaction->id,
            'company_id' => $company_id,
            'role_id' => 5,
            'availability_status' => 'reserved',
        );

        $companyUserTransaction = $this->createCompanyUser($company_user);

        $user_data = [
            'host_name' => Auth::user()->first_name . ' ' . Auth::user()->last_name,
            'title' => 'ConX Invitation',
            'email' => $email_address,
            'email_token' => $token,
            'company_name' => $this->getCurrentUserCompanyName()->name,
            'type' => 'Worker',
        ];

        if (!$workerTransaction || !$companyUserTransaction) {
            return ['success' => false, 'message' => "Error in proccessing you request"];
        } else {
            DB::commit();
            ProcessSendEmailWorkerInvitation::dispatch($email_address, $user_data)->onConnection('jobs_emails')->onQueue('sendemail');
            return ['success' => true];
        }
    }

    public function createWorker($data)
    {
        return Worker::create($data);
    }

    public function createCompanyUser($data)
    {
        return CompanyUser::create($data);
    }

    public function checkIfCompanyEmployee($email_address, $company_id)
    {
        $email_address = strtolower($email_address);
        
        $data = Worker::select(
            'company_users.company_id',
            'workers.id',
            'workers.first_name',
            'workers.email_verified_at',
        )
            ->leftJoin('company_users', 'company_users.worker_id', 'workers.id')
            ->where('workers.email_address', $email_address)
            ->first();
        if ($data) {
            if ($data->company_id == $company_id && $data->first_name == 'Temp' && $data->email_verified_at == null) {
                return "Email " . $email_address . " was already invited. Resend invite on Pending Invites page.";
            } else if ($data->company_id === $company_id) {
                return "Email " . $email_address . " was already been used in your company. Manage user roles directly on the Users page.";
            } else {
                return "Email " . $email_address . " was already been used by another company.";
            }
        } else {
            return "Email " . $email_address . " was already been used but temporarily disabled.";
        }
    }

    public function multi_unique($data)
    {
        return $result = array_reverse(
            array_values(
                array_column(
                    array_reverse($data),
                    null,
                    'email_address' //email index
                )
            )
        );
    }

    public function checkEmail($payload)
    {
        $company_id =  $this->companyID;

        $rules = [
            'email_address' => 'unique:workers',
        ];

        $validator = Validator::make($payload->all(), $rules);

        if($validator->fails())
        {
            $error = $validator->errors()->first();
            $index = preg_replace('/\D/', '', $error);
            $response =  $this->checkIfCompanyEmployee($payload->email_address, $company_id);
            return response()->json(['errors' => $response])->setStatusCode(200);
        }else{
            return response()->json(['success' => ['No error']])->setStatusCode(201);
        }
    }

}
