<?php

namespace App\Modules\Company\Jobseeker;

use App\Events\Company\JobseekerNotificationEvent;

use App\Models\JobseekerApplicant;
use App\Models\JobseekerCompanyRefs;
use App\Models\JobseekerInvitation;
use App\Models\JobseekerNotification;
use App\Traits\CheckEmployeeCountTraits;
use App\Traits\CreateUserActionTraits;
use App\Traits\SearchTraits;
use App\Traits\SortingTraits;
use App\Traits\UserTraits;
use App\Traits\ValidatorTraits;
use Illuminate\Support\Facades\DB;

class Applicant
{
    use CreateUserActionTraits, SortingTraits, SearchTraits, ValidatorTraits, UserTraits, CheckEmployeeCountTraits;
    public $companyId;

    public function __construct()
    {
        $this->companyId = $this->getCurrentUser()->company_id;
    }
    
    public function fetchApplicants($payload)
    {

        $company_id = $this->companyId;
        // sorting
        $sortField = $this->sortField($payload, 'created_at'); // first_name = default column to search
        $sortOrder = $this->sortOrder($payload, 'asc');

        // searching
        $nameSearch = $this->searchField($payload->name);

        $applicants = JobseekerApplicant::select(
            'jobseeker_applicants.id',
            'jobseeker_applicants.worker_id',
            'jobseeker_applicants.date_added',
            'jobseeker_applicants.status',
            'jobseeker_applicants.remarks',
            'jobseeker_applicants.created_at',
            'jobseeker_applicants.updated_at as date_updated',
            DB::raw('CONCAT(workers.first_name, " ", workers.last_name) as name'),
            'workers.availability_start_date',
            'workers.availability_end_date',

        )
            ->when(!empty($nameSearch), function ($query) use ($nameSearch) {
                return $query->where(function ($query) use ($nameSearch) {
                    $query->where('workers.first_name', 'LIKE', $nameSearch . '%')
                        ->orWhere('workers.last_name', 'LIKE', $nameSearch . '%');
                });
            })
            ->leftJoin('workers', 'workers.id', '=', 'jobseeker_applicants.worker_id')
            ->where('jobseeker_applicants.company_id', $company_id)
            ->orderBy($sortField, $sortOrder)
            ->paginate(20);

        return response()->json($applicants);
    }

    public function updateRemark($payload)
    {
        $remark = tap(JobseekerApplicant::where('id', $payload->id))->update(['remarks' => $payload->remark])->first();
        $saveUserAction = $this->createUserAction('Updated the remarks for applicant ' . $payload->name);

        if ($remark && $saveUserAction) {
            return response()->json(['success' => 'Remark successfully updated.'])
                ->setStatusCode(201);
        } else {
            return response()->json(['error' => ['Unable to update remark.']])
                ->setStatusCode(201);
        }

    }

    public function removeApplicant($id, $payload)
    {
        $applicant = JobseekerApplicant::where('id', $id)->delete();
        $saveUserAction = $this->createUserAction('Deleted applicant ' . $payload->name);

        if ($applicant && $saveUserAction) {
            return response()->json(['success' => 'Applicant Successfully Removed.'])
                ->setStatusCode(201);
        } else {
            return response()->json(['error' => ['Unable to release employee.']])
                ->setStatusCode(201);
        }
    }

    public function addApplicant($payload)
    {
        $company_id = $this->companyId;
        $jobseeker_id = $payload->id;

        $validation = JobseekerApplicant::select('company_id')->where('company_id', $company_id)->where('worker_id', $jobseeker_id)->first();

        if ($validation) {
            if ($validation->company_id == $company_id) {
                return response()->json(['error' => $payload->name . ' was already added as applicant.']);
            }
        }

        DB::beginTransaction();

        $applicant_data = array(
            'company_id' => $company_id,
            'worker_id' => $jobseeker_id,
            'status' => 'in-progress',
            'date_added' => now(),
        );

        $applicant_transaction = $this->createApplicant($applicant_data);

        $applicant_notif = array(
            'company_id' => $company_id,
            'worker_id' => $jobseeker_id,
            'type' => 'added-applicant',
            'is_read' => 0,
            'description' => $this->getCurrentUserCompanyName()->name . ' added you as an applicant',
        );

        $applicant_notif = $this->createApplicantNotif($applicant_notif);
        event(new JobseekerNotificationEvent($applicant_notif)); //Event for realtime notif

        $saveUserAction = $this->createUserAction('Added ' . $payload->name . ' as an applicant');

        if ($applicant_transaction && $applicant_notif && $saveUserAction) {
            DB::commit();
            return response()->json(['success' => 'success']);
        } else {
            DB::rollBack();
            return response()->json(['error' => 'error']);
        }

    }

    public function createApplicant($data)
    {
        return JobseekerApplicant::create($data);
    }

    public function inviteApplicantAsWorker($payload)
    {
        $company_id = $this->companyId;
        $name = $payload->name;

        /*========================================================================================================
        Check subscription
        ========================================================================================================*/
        $validate = $this->employeeCountValidation($company_id);
        if ($validate) {
            return $validate;
        }

        /* Check jobseeker if currently on a connections to company as workers*/
        $validation = $this->checkConnection($payload->worker_id);
        if ($validation) {
            return response()->json(['errors' => ['Unable to invite applicant, currently in a contract with a company.']])->setStatusCode(201);
        }

        DB::beginTransaction();

        $invitation_data = array(
            'hourly_rate' => $payload->hourly_rate,
            'message' => $payload->message,
            'notes' => $payload->notes,
            'status' => 'Pending',
            'date_invited' => now(),
        );
        $transact_invitation = $this->create_invitation($invitation_data);

        $applicant_notif = array(
            'company_id' => $company_id,
            'worker_id' => $payload->worker_id,
            'invitation_id' => $transact_invitation->id,
            'type' => 'invitation',
            'is_read' => 0,
            'description' => $this->getCurrentUserCompanyName()->name . ' invited you.',
        );

        $applicant_notif = $this->createApplicantNotif($applicant_notif);
        event(new JobseekerNotificationEvent($applicant_notif)); //Event for realtime notif

        $transact_update_status = $this->update_applicant_status($payload->applicant_id, $name);

        if ($transact_invitation && $transact_update_status && $transact_update_status) {
            DB::commit();
            //Send email notification dapat. sa jobseeker
            return response()->json(['status' => 'success']);
        } else {
            DB::rollBack();
            return response()->json(['status' => 'error']);
        }
    }

    public function createApplicantNotif($data)
    {
        return JobseekerNotification::create($data);
    }

    public function checkConnection($worker_id)
    {
        return JobseekerCompanyRefs::where('worker_id', $worker_id)->where('date_end', null)
            ->first();
    }

    public function checkReinvite($id)
    {
        $data = $this->checkConnection($id);
        if ($data) {
            return response()->json(['errors' => 'Unable to invite applicant, currently in contract with a company.']);
        } else {
            return response()->json(['success' => 'Available']);
        }
    }

    public function create_invitation($invitation_data)
    {
        return JobseekerInvitation::create($invitation_data);
    }

    public function update_applicant_status($id, $name)
    {
        $data = JobseekerApplicant::where('id', $id)->first();
        if ($data) {
            if ($data->status == 'Declined' || $data->status == 'Invited') {
                //User Logs/Report
                $this->createUserAction("Re-invited applicant " . $name);
                return JobseekerApplicant::where('id', $id)->update(['status' => 'Re-invited']);
            } else if ($data->status == 'Accepted' || $data->status == 'Re-invited') {
                return true;
            } else {
                //User Logs/Report
                $this->createUserAction("Invited applicant " . $name);
                return JobseekerApplicant::where('id', $id)->update(['status' => 'Invited']);
            }
        } else {
            return true;
        }
    }

    public function updateInterviewStatus($payload)
    {

        if ($payload->status == 'in-progress') {
            $status = 'in-progress';
        } elseif ($payload->status == 'resume-screening') {
            $status = 'resume screening';
        } elseif ($payload->status == 'interview') {
            $status = 'for interview';
        } elseif ($payload->status == 'submission') {
            $status = 'for submission of requirements';
        } elseif ($payload->status == 'failed') {
            $status = 'failed';
        } elseif ($payload->status == 'passed') {
            $status = 'passed';
        }

        $transactStatus = tap(JobseekerApplicant::where('id', $payload->id))->update(['status' => $payload->status])->first();

        $saveUserAction = $this->createUserAction('Updated the status of applicant ' . $payload->name . ' into ' . $status);

        if ($transactStatus && $saveUserAction) {
            return response()->json(['success' => 'Status successfully updated.'])
                ->setStatusCode(201);
        } else {
            return response()->json(['error' => ['Unable to update status.']])
                ->setStatusCode(201);
        }

    }

}
