<?php

namespace App\Modules\Company\Users\Invitation;

use Carbon\Carbon;

use App\Jobs\Company\ProcessFileUserInvitation;

use App\Models\Role;
use App\Models\Worker;

use App\Traits\CheckEmployeeCountAvailableTraits;
use App\Traits\CreateUserActionTraits;
use App\Traits\GenerateAndValidateWorkerID;
use App\Traits\RemoveDuplicateEmailTraits;
use App\Traits\ValidatorTraits;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class FileInvitation
{
    use GenerateAndValidateWorkerID, ValidatorTraits, CheckEmployeeCountAvailableTraits, RemoveDuplicateEmailTraits, CreateUserActionTraits;

    public function invite($payload)
    {
        if (request()->has('file')) {

            /* Validate file extension */
            $rules = array(
                'file' => 'required|mimes:csv,txt',
            );
            $validate = $this->validateRequest($payload, $rules);
            if ($validate) {
                return $validate;
            }

            $data = array_map('str_getcsv', file($payload->file));

            /* Validate header rows */
            if (!$this->checkHeaderFormat($data[0])) {
                return response()->json(['errors' => 'Invalid file format. Please use the given sample format'])->setStatusCode(200);
            };

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

            /* remove header  */
            unset($data[0]);

            /* removes duplicate value in the file */
            $data = $this->multi_unique($data);

            /* fetch all existing item of a file, params = all email in first index  */
            $existing = $this->getExistingEmails(array_column($data, 0));

            /* return data where is not existed on dbase  */
            $data = $this->cleanData($data, $existing);

            $hostname = Auth::user()->first_name . ' ' . Auth::user()->last_name;
            $compname = $this->getCurrentUserCompanyName()->name;

            // Chunking file, divide into parts
            $chunks = array_chunk($data, 10);
            $tableHeader = ['email_address', 'rate', 'date_hired'];
            $batch = Bus::batch([])->onConnection('jobs_emails')->name('Employee File invitation')->onQueue('sendemail')->allowFailures(true)->dispatch();
            $unsend = [];

            foreach ($chunks as $key => $chunk) {
                $hold = [];

                foreach ($chunk as $user) {
                    $data = [];
                    $token = hash('sha256', $plainTextToken = Str::random(80));

                    //Check for empty columns [0] Email address , [1] Hourly Rate, [2] Date Hired (optional), [3] Roles, [4] Admin verified, 
                    if (!$user[0] || !$user[1] || !$user[3] || !isset($user[4])) {
                        if ($user[0] != "") {
                            //user who has incomplete data in the file
                            array_push($unsend, $user);
                        }
                    } else {
                        /* Prepare user data */
                        $data['email_address'] = strtolower($user[0]);
                        $data['rate'] = $user[1];
                        $data['date_hired'] = $user[2]? Carbon::parse($user[2]): null;
                        $data['email_verification_code'] = strtolower($user[4]) == "yes" ? $token . "_admin_verified" : $token;
                        // $data['email_verified_at'] = Carbon::now();
                        $data['first_name'] = 'Temp';
                        $data['last_name'] = 'Temp';
                        $data['zipcode'] = '00000';
                        $data['password'] = Hash::make('123456789');
                        $data['roles'] = $this->convertRolesToID(explode("|", $user[3]));
                        array_push($hold, (object) $data);
                    }
                }
                // return $hold;
                $batch->add(new ProcessFileUserInvitation($hold, $userData->company_id, $hostname, $compname));
            }
            $this->createUserAction("Invited user using file upload");
            return response()->json(['batch' => $batch, 'duplicate' => $existing, 'unsend' => (array) $unsend])->setStatusCode(201);
        }

        return response()->json(['errors' => 'No file uploaded.'])->setStatusCode(201);
    }

    public function getBatch($id)
    {
        return Bus::findBatch($id);
    }

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

    public function getExistingEmails($emails)
    {
        return DB::table('workers')
            ->select('email_address')
            ->whereIn('email_address', (array) $emails)
            ->get();
    }

    public function checkHeaderFormat($headers)
    {

        if (count($headers) == 5) {
            if (in_array("Email Address", $headers) || in_array("Hourly Rate", $headers) || in_array("Date Hired", $headers) || in_array("Roles", $headers) || in_array("Admin Verified", $headers)) {
                return true;
            }
            return false;
        }
        return false;
    }

    public function getUserInvitationFileFormat()
    {
        return Storage::disk('csv')->get('user-invitation-format.csv');
    }

    public function convertRolesToID($roles)
    {
        $data = [];
        foreach ($roles as $role) {
            if ($role == "owner") {
                array_push($data, $this->getRoleId("Owner / Admin"));
            } else if ($role == "manager") {
                array_push($data, $this->getRoleId("Project Manager"));
            } else if ($role == "supervisor") {
                array_push($data, $this->getRoleId("Supervisor"));
            } else if ($role == "accountant") {
                array_push($data, $this->getRoleId("Accountant"));
            } else if ($role == "worker") {
                array_push($data, $this->getRoleId("Worker"));
            }
        }

        return $data;
    }

    public function getRoleId($name)
    {
        $data = Role::select('id')->where('name', $name)->first();
        return $data->id;
    }
}