<?php

namespace App\Modules\Company;

use App\Traits\SearchTraits;
use App\Traits\SortingTraits;
use App\Traits\ValidatorTraits;
use App\Traits\CalculateBillableRateTrait;
use App\Traits\UserTraits;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

use App\Http\Resources\Company\Experience as CompanyExperienceResource;
use App\Models\CompanyExperience;
use App\Models\CompanyBurdenRate;
use App\Models\WorkerExperience;
use App\Models\Availabilities;
use App\Models\Worker;

class Experiences{
    use SortingTraits, SearchTraits, ValidatorTraits, UserTraits, CalculateBillableRateTrait;

    public function fetchExperiences($payload)
    {
        $sortField = $this->sortField($payload, 'name'); // name = default column to search
        $sortOrder = $this->sortOrder($payload);
        $companyID = $this->getCurrentUser()->company_id;
        $burdenRateType = $payload->burden_rate_type;

        return CompanyExperienceResource::collection(
            CompanyExperience::select(
                'company_experiences.name',
                'company_experiences.id as company_experience_id',
                'company_burden_rate.id as burden_rate_id',
                'company_burden_rate.burden_rate',
                'company_burden_rate.burden_rate_type',
                'company_burden_rate.company_id',
            )
                ->join('company_burden_rate', 'company_burden_rate.company_experience_id', 'company_experiences.id')
                ->where("company_experiences.company_id", $companyID)
                ->where("company_burden_rate.company_id", $companyID)
                ->when(!empty($burdenRateType), function ($query) use ($burdenRateType) {
                    return $query->whereIn('company_burden_rate.burden_rate_type', $burdenRateType);
                })
                ->whereNull('company_burden_rate.deleted_at')
                ->orderBy($sortField, $sortOrder)
                ->paginate(20)
        )
            ->response()
            ->setStatusCode(201);
    }

    public function fetchExperienceForMixins(){
        $companyID = $this->getCurrentUser()->company_id;
        $experiences = CompanyExperience::select(
            'company_experiences.id',
            'company_experiences.name',
            'company_burden_rate.id as burden_rate_id',
        )
            ->orderBy('name', 'asc')
            ->join('company_burden_rate', 'company_burden_rate.company_experience_id', 'company_experiences.id')
            ->whereNull('company_burden_rate.deleted_at')
            ->where('company_experiences.company_id', $companyID)
            ->get();
        return response()->json($experiences);
    }

    public function fetchDetails($id)
    {
        return CompanyExperienceResource::collection(
            CompanyExperience::select(
                'company_burden_rate.company_id',
                'company_burden_rate.id',
                'company_burden_rate.company_experience_id',
                'company_burden_rate.burden_rate',
                'company_burden_rate.burden_rate_type',
                'company_experiences.name'
            )
                ->join('company_burden_rate', 'company_burden_rate.company_experience_id', 'company_experiences.id')
                ->where('company_experiences.id', $id)
                ->limit(1)
                ->get()
        )
            ->response()
            ->setStatusCode(201);
    }

    public function updateCompanyExperience($payload)
    {
        $rules = array(
            'burdenRateAmount' => 'required',
            'burdenRateID' => 'required',
            'burdenRateType' => 'required',
            'companyExperienceID' => 'required',
            'name' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        $companyID = $this->getCurrentUser()->company_id;
        // Check for duplicate company experience
        $validate = $this->checkCompanayExperience($payload->name, $companyID, $payload->companyExperienceID);
        if ($validate) {
            return response()->json(['errors' => 'Company Experience is already taken.'])->setStatusCode(201);
        } 

        DB::beginTransaction();

        

        $companyExperienceData = array(
            'name' => $payload->name,
        );
        $companyExperienceTransaction = $this->updateCompanyExperienceData($payload->companyExperienceID, $companyExperienceData);

        $companyBurdenRateData = array(
            'burden_rate' => $payload->burdenRateAmount,
            'burden_rate_type' => $payload->burdenRateType,
        );
        $companyBurdenRateTransaction = $this->updateCompanyBurdenRateData($payload->burdenRateID, $companyBurdenRateData);

        $workersUpdateBillingRateTransaction = $this->updateBillableRateOfWorkers($payload->burdenRateType, $payload->burdenRateAmount, $payload->burdenRateID);

        // preparing worker availability data to be updated on database

        $listOfWorkers= $this->getWorkersData($payload->burdenRateID, $companyID);

        foreach($listOfWorkers as $data){
            $workerID = $data->id;
            $hourlyRate = $data->flat_rate;
            $burdenRate = $payload->burdenRateAmount;
            $burdenRateType = $payload->burdenRateType;

            if($burdenRate || $burdenRateType){
                $loadedRate = $burdenRateType == 'percent'? $hourlyRate + (($burdenRate * 0.01) * $hourlyRate): $hourlyRate + $burdenRate;
            }

            $workerAvailabilityData = array(
                'rate' => $loadedRate? $loadedRate: $hourlyRate,
            );

            $updateWorkerAvailabilityTransaction = $this->updateWorkerAvailabilities($workerID, $workerAvailabilityData);

            if(!$updateWorkerAvailabilityTransaction){
                return response()->json(['errors' => 'Something went wrong. Please reload the page'])->setStatusCode(201);
            }
        }



        if ($companyExperienceTransaction && $companyBurdenRateTransaction && $workersUpdateBillingRateTransaction) {
            DB::commit();
            return response()->json(['success' => 'Data successfully updated.'])->setStatusCode(201);
        } else {
            DB::rollBack();
            return response()->json(['errors' => 'Something went wrong. Please reload the page'])->setStatusCode(201);
        }
    }

    public function updateCompanyExperienceData($id, $data)
    {
        return CompanyExperience::where('id', $id)->update($data);
    }

    public function updateCompanyBurdenRateData($id, $data)
    {
        return CompanyBurdenRate::where('id', $id)->update($data);
    }
    public function updateBillableRateOfWorkers($burdenRateType, $burdenRateAmount, $burdenRateID)
    {
        $companyID = $this->getCurrentUser()->company_id;
        $listOfWorkers = Worker::select(
                'workers.id',
                'workers.flat_rate as hourly_rate',
                'workers.overhead_charge as overheadAmount',
                'workers.overhead_type as overheadType')
                ->join('worker_experiences', 'worker_experiences.worker_id', 'workers.id')
                ->join('company_experiences', 'company_experiences.id', 'worker_experiences.experience_id')
                ->join('company_burden_rate', 'company_burden_rate.id', 'worker_experiences.burden_rate_id')
                ->join('company_users', 'company_users.worker_id', 'workers.id')
                ->join('companies', 'companies.id', 'company_users.company_id')
                ->where('company_users.company_id', $companyID)
                ->where('company_burden_rate.id', $burdenRateID)
                ->where('company_users.role_id', 5)
                ->whereNotNull('workers.email_verified_at')
                ->get();

        if(!$listOfWorkers){
            return false;
        }

        forEach($listOfWorkers as $worker){
            $worker->burden_rate = $burdenRateAmount;
            $worker->burden_rate_type = $burdenRateType;
            $computationTransaction = $this->newComputationOfBillableRate($worker);

            $updateWorkerRates = array(
                'flat_rate' => $computationTransaction->originalRate,
                'rate' => $computationTransaction->billableRate, 
                'overhead_charge' => $computationTransaction->overHeadAmount,
                'overhead_type' => $computationTransaction->overHeadType,
            );

            $workerUpdateRate = Worker::where('id', $worker->id)->update($updateWorkerRates);

            if(!$workerUpdateRate){
                return false;
            }

        }   
        return true;    
    }

    public function createCompanyExperience($payload)
    {
        $rules = array(
            'burdenRateAmount' => 'required',
            'burdenRateType' => 'required',
            'name' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        } 
        
        $companyID = $this->getCurrentUser()->company_id;

        // Check for duplicate expertise
        $validate = $this->fetchCompanayExperience($payload->name, $companyID);
        if ($validate) {
            return response()->json(['errors' => 'Company Experience is already added.'])->setStatusCode(201);
        } 

        DB::beginTransaction();

        $companyExperienceData = array(
            'name' => $payload->name,
            'company_id' => $companyID,
        );
        $companyExperienceTransaction = $this->saveCompanyExperienceData($companyExperienceData);

        $companyBurdenRateData = array(
            'burden_rate' => $payload->burdenRateAmount,
            'burden_rate_type' => $payload->burdenRateType,
            'company_id' => $companyID,
            'company_experience_id' => $companyExperienceTransaction->id,
        );
        $companyBurdenRateTransaction = $this->saveCompanyBurdenRateData($companyBurdenRateData);

        if ($companyExperienceTransaction && $companyBurdenRateTransaction) {
            DB::commit();
            return response()->json(['success' => 'New Experience Saved Succesfully.'])->setStatusCode(201);
        } else {
            DB::rollBack();
            return response()->json(['errors' => 'Something went wrong. Please reload the page'])->setStatusCode(201);
        }
    }

    public function fetchCompanayExperience($name, $companyID){
        return CompanyExperience::where('name', $name)
            ->where('company_id', $companyID)
            ->first();
    }

    public function checkCompanayExperience($name, $companyID, $companyExperienceID){
        return CompanyExperience::where('name', $name)
            ->where('company_id', $companyID)
            ->where('id', '!=', $companyExperienceID)
            ->first();
    }
    
    public function saveCompanyExperienceData($data)
    {
        return CompanyExperience::create($data);
    }

    public function saveCompanyBurdenRateData($data)
    {
        return CompanyBurdenRate::create($data);
    }

    public function removeCompanyExperienceAndBurdenRate($payload)
    {
        $rules = array(
            'company_experience_id' => 'required',
            'burden_rate_id' => 'required',
            'name' => 'required',
        );
        $validate = $this->validateRequest($payload, $rules);
        if ($validate) {
            return $validate;
        }

        $companyExperienceID = $payload->company_experience_id;
        
        //validate if used
        if($this->isCompanyExperienceUsed($companyExperienceID)){
            return response()->json(['errors' => 'Sorry, company experience is currently used.']);
        }

        DB::beginTransaction();

        $companyExperienceTransaction = $this->removeCompanyExperience($companyExperienceID);

        $companyBurdenRateExperience = $this->removeCompanyBurdenRate($companyExperienceID);

        if ($companyExperienceTransaction && $companyBurdenRateExperience) {
            DB::commit();
            return response()->json(['success' => 'Data deleted successfully.'])->setStatusCode(201);
        } else {
            DB::rollBack();
            return response()->json(['errors' => 'Something went wrong. Please reload the page',
                'companyExperienceTransaction' => $companyExperienceTransaction,
                'companyBurdenRateExperience' => $companyBurdenRateExperience,
            ])->setStatusCode(201);
        }
    }

    public function isCompanyExperienceUsed($experienceID){
        return WorkerExperience::where('experience_id', $experienceID)->first();
    }

    public function removeCompanyExperience($id)
    {
        return CompanyExperience::where('id', $id)->delete();
    }

    public function removeCompanyBurdenRate($companyExperienceID)
    {
        return CompanyBurdenRate::where('company_experience_id', $companyExperienceID)->delete();
    }

    public function usage($id)
    {
        $workers = WorkerExperience::where('experience_id', $id)->get();
        return $workers->count();
    }
    
    public function updateWorkerAvailabilities($workerID, $workerAvailabilityData){
        return Availabilities::where('worker_id', $workerID)
            ->where('worker_type', 'inhouse')
            ->update($workerAvailabilityData);
    }

    public function getWorkersData($burdenRateID, $companyID){

        return Worker::select('workers.id', 'flat_rate')
                        ->join('worker_experiences', 'worker_experiences.worker_id', '=', 'workers.id')
                        ->join('company_users', 'company_users.worker_id', '=', 'workers.id')
                        ->where('burden_rate_id', $burdenRateID)
                        ->where('company_id', $companyID)
                        ->get();
    }
}