<?php

namespace App\Modules\Company\Users;

use App\Models\Company as AppCompany;
use App\Models\CompanyUser;
use App\Http\Resources\Company;
use App\Jobs\Company\ProcessSendEmailAdminVerifiedNotice;
use App\Jobs\Company\ProcessSendEmailForNewCompanyUser;
use App\Jobs\Company\ProcessSendEmailWorkerInvitation;
use App\Models\PasswordResets;
use App\Traits\CheckEmployeeCountAvailableTraits;
use App\Traits\CreateUserActionTraits;
use App\Traits\GenerateAndValidateWorkerID;
use App\Traits\SendSMSTraits;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;

use App\Models\Worker;
use Carbon\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class UserInvitation
{
    use GenerateAndValidateWorkerID, CheckEmployeeCountAvailableTraits, CreateUserActionTraits, SendSMSTraits;

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

        /******************** ********************
        Validation in worker email
         */

        $rules = [
            'data' => 'required|array',
            'data.*.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);

        // return response('xxx', 401);

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


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

        return $email_verification;
    }

    public function resend($id)
    {   
        $isInviteLink = false;
        $roles = [];
        $worker = Worker::select(
            'workers.id',
            'workers.first_name',
            'workers.last_name',
            'workers.email_address',
            'workers.email_verification_code',
            'workers.phone_num'
        )
            ->with('roles:worker_id,name,roles.id')
            ->where('workers.id', $id)
            ->first();
        
        

        foreach ($worker->roles as $role) {
            array_push($roles, $role->id);
        }

        if ($worker) {
            $first_name = $worker->first_name;
            $last_name = $worker->last_name;
            $email_address = $worker->email_address;
            $emailVerificationCode = $worker->email_verification_code;
            $roles = $worker->roles;
            if (count($worker->roles) == 1 && $roles[0]->id == 5) { // 5 = Worker
                // check if manually added or invited
                if ($worker->phone_num) {
                    $mobileLink = env('MOBILE_LINK');
                    $verificationUrl = $mobileLink . '/setup-account?token=' . $emailVerificationCode;
                    $worker_data = [
                        'first_name' => $first_name,
                        'last_name' => $last_name,
                        'email_address' => $email_address,
                        'verification_url' => $verificationUrl,
                        'from-invite-link' => false,
                        'company_name' => $this->getCurrentUserCompanyName()->name,
                        'role' => $roles,
                    ];
                    ProcessSendEmailForNewCompanyUser::dispatch($email_address, $worker_data)->onConnection('jobs_emails')->onQueue('sendemail');
                } else {
                    $user_data = [
                        'host_name' => Auth::user()->first_name . ' ' . Auth::user()->last_name,
                        'title' => 'ConX Invitation',
                        'email' => $email_address,
                        'email_token' => $emailVerificationCode,
                        'company_name' => $this->getCurrentUserCompanyName()->name,
                        'type' => 'Worker',
                    ];
                    ProcessSendEmailWorkerInvitation::dispatch($email_address, $user_data)->onConnection('jobs_emails')->onQueue('sendemail');
                }
            } else {
                if ($worker->phone_num) {
                    // return "added";
                    $appLink = env('APP_URL');
                    $verificationUrl = $appLink . '/setup-account?token=' . $emailVerificationCode;
                    $worker_data = [
                        'first_name' => $first_name,
                        'last_name' => $last_name,
                        'email_address' => $email_address,
                        'verification_url' => $verificationUrl,
                        'from-invite-link' => false,
                        'company_name' => $this->getCurrentUserCompanyName()->name,
                        'role' => $roles,
                    ];
                    ProcessSendEmailForNewCompanyUser::dispatch($email_address, $worker_data)->onConnection('jobs_emails')->onQueue('sendemail');
                } else {
                    // return "invited";
                    $user_data = [
                        'host_name' => Auth::user()->first_name . ' ' . Auth::user()->last_name,
                        'title' => 'ConX Invitation',
                        'email' => $email_address,
                        'email_token' => $emailVerificationCode,
                        'company_name' => $this->getCurrentUserCompanyName()->name,
                        'type' => 'User',
                    ];
                    ProcessSendEmailWorkerInvitation::dispatch($email_address, $user_data)->onConnection('jobs_emails')->onQueue('sendemail');
                }
            }

            // create user action for reports
            $this->createUserAction("Resend invitation for " . $email_address);
            return response()->json(['success' => 'Email sent successfully.'])->setStatusCode(201);
        } else {
            return response()->json(['error' => 'Server error.']);
        }
    }

    public function cancel($payload, $id)
    {
        $workerDelete = Worker::where('workers.id', $id)->delete();
        $companyUserDelete = CompanyUser::where('worker_id', $id)->delete();

        // create user action for reports
        $this->createUserAction("Remove the invitation for " . $payload->email);

        if ($workerDelete && $companyUserDelete) {
            return response()->json(['success' => 'Invitation remove successfully.'])->setStatusCode(201);
        } else {
            return response()->json(['error' => 'Server error.']);
        }
    }

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

        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);
        }
        $company_details = AppCompany::select('zipcode')->where('id', $company_id)->first();
        $worker_data = array(
            'worker_id' => $workerGeneratedId,
            'email_address' => $email_address,
            'first_name' => 'Temp',
            'last_name' => 'Temp',
            'password' => Hash::make(Str::random(8)),
            'zipcode' => $company_details->zipcode,
            'rate' => $user['hourly_rate'],
            'date_hired' => $user['date_hired'] ? Carbon::parse($user['date_hired']) : null,
            'email_verification_code' => $token,
        );

        $workerTransaction = $this->createWorker($worker_data);
        if (str_contains($token, 'admin_verified')) {
            PasswordResets::create([
                'email' => $email_address,
                'token' => $token,
            ]);
        }
        $roles = $user['roles_acquired'];
        foreach ($roles as $role) {
            $company_user = array(
                'worker_id' => $workerTransaction->id,
                'company_id' => $company_id,
                'role_id' => $role,
                'availability_status' => 'reserved',
            );
            $companyUserTransaction = $this->createCompanyUser($company_user);
        }

        if (in_array(5, $roles) && count($roles) > 1) {
            $is_user = true;
        } else if (in_array(5, $roles) && count($roles) == 1) {
            $is_user = false;
        } else {
            $is_user = true;
        }

        $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' => ($is_user) ? 'User' : 'Worker',
        ];

        if (!$workerTransaction || !$companyUserTransaction) {
            return ['success' => false, 'message' => "Error in proccessing you request "];
        } else {
            DB::commit();
            ProcessSendEmailWorkerInvitation::dispatch($email_address, $user_data)->onQueue('sendemail')->onConnection('jobs_emails');
            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)
    {
        $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 verifyEmailAsAdmin($payload)
    {
        $workerData = Worker::where('id', $payload->worker_id)->first();

        if (!$workerData) {
            return response()->json(['errors' => 'Something went wrong while processing data.']);
        }

        $token = ($workerData->email_verification_code) ? $workerData->email_verification_code . "_admin_verified" : hash('sha256', Str::random(50)) . "_admin_verified";
        $workerData->email_verification_code = $token;
        $workerData->is_active = 'true';
        $workerData->save();

        $userData = $this->getCurrentUser();
        $email_address = $workerData->email_address;
        $user_data = [
            'company_name' => $userData->company_name,
            'email_token' => $token,
            'type' => $payload->isWorkerOnly ? 'Worker' : 'User',
        ];

        //Send Email notification
        ProcessSendEmailAdminVerifiedNotice::dispatch($email_address, $user_data)->onConnection('jobs_emails')->onQueue('sendemail');

        if ($userData->phone_num) {
            $phone_message = $this->sendMessage($userData->phone_num, '[ConX] Email Verified by admin: Please read the email sent to your email address.');
            // $phone_message = $this->sendMessage($userData->phone_num, '[ConX] Email Verified by admin: Please read the email sent to your address. You can also go to' . env('APP_FRONT_URL') . '?adminverified=true and Login your account using ' . $userData->email_address . ' as your email address.');
        }

        if ($workerData) {
            return response()->json(['success' => 'User successfully verified!']);
        }
    }
}
