<?php

namespace App\Listeners\Company\Rating;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use App\Models\CompanyRatingAggregate;
use Illuminate\Support\Facades\Log;
use App\Events\Company\Rating\ProcessAggregateCompanyRatingEvent;

class ProcessAggregateCompanyRatingListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  object  $event
     * @return void
     */
    public function handle(ProcessAggregateCompanyRatingEvent $event)
    {
        $newCompanyRate = $event->newAddedCompanyRate; /// new additional rate
        
        $type = $newCompanyRate->type;

        if($type ==  'borrowing'){
            $this->processBorrowingRate($newCompanyRate);
            Log::channel('background')->info('proccess borrowing aggregate job');
        }else if($type == 'loaning'){
            Log::channel('background')->info('proccess loaning aggregate job');
            $this->processLoaningRate($newCompanyRate);
        }
    }

    public function processBorrowingRate($newCompanyRate){

        $companyID = $newCompanyRate->company_id;
        $rate = (int) $newCompanyRate->rate;
        $type = $newCompanyRate->type;
        $aggregatedData = $this->checkIfCompanyAggregateExist($companyID, $type);
        
        if(!$aggregatedData){
            $defaultJsonRate = array(
                'rate_1' => 0,
                'rate_2' => 0,
                'rate_3' => 0,
                'rate_4' => 0,
                'rate_5' => 0,
            );

            $detected = array_slice($defaultJsonRate, $rate - 1 , 1, true); //get the element base on the rate value, #1: json data. #2: offfset, #3: length, #4: preserve_keys 
            $rateToBeUpdated = array_key_first($detected); //get the element key
            $defaultJsonRate[$rateToBeUpdated] =  1;   //set the first rate count
            $workerAggregatedRate = array(
                'company_id' => $companyID,
                'average_rate' => $rate,
                'type' => 'borrowing',
                'rates' => json_encode($defaultJsonRate),
            );
            CompanyRatingAggregate::create($workerAggregatedRate);

        }else{

            $currentJsonRate = (array) json_decode($aggregatedData->rates);

            $detected = array_slice($currentJsonRate, $rate - 1 , 1, true); //get the element base on the rate value, #1: json data. #2: offfset, #3: length, #4: preserve_keys
            $rateToBeUpdated = array_key_first($detected); //get the element key
            $currentJsonRate[$rateToBeUpdated] = $currentJsonRate[$rateToBeUpdated] + 1;

            $workerAggregatedRate = array(
                'company_id' => $companyID,
                'average_rate' => $this->computeAverage($currentJsonRate),
                'type' => 'borrowing',
                'rates' => json_encode($currentJsonRate),
            );
            CompanyRatingAggregate::where('company_id', $companyID)
                ->where('type', 'borrowing')
                ->update($workerAggregatedRate);
        }
    }

    public function processLoaningRate($newCompanyRate){

        $companyID = $newCompanyRate->company_id;
        $rate = (int) $newCompanyRate->rate;
        $type = $newCompanyRate->type;
        $aggregatedData = $this->checkIfCompanyAggregateExist($companyID, $type);

        if(!$aggregatedData){
            $defaultJsonRate = array(
                'rate_1' => 0,
                'rate_2' => 0,
                'rate_3' => 0,
                'rate_4' => 0,
                'rate_5' => 0,
            );

            $detected = array_slice($defaultJsonRate, $rate - 1 , 1, true); //get the element base on the rate value, #1: json data. #2: offfset, #3: length, #4: preserve_keys 
            $rateToBeUpdated = array_key_first($detected); //get the element key
            $defaultJsonRate[$rateToBeUpdated] =  1;   //set the first rate count
            $workerAggregatedRate = array(
                'company_id' => $companyID,
                'average_rate' => $rate,
                'type' => 'loaning',
                'rates' => json_encode($defaultJsonRate),
            );
            CompanyRatingAggregate::create($workerAggregatedRate);

        }else{

            $currentJsonRate = (array) json_decode($aggregatedData->rates);

            $detected = array_slice($currentJsonRate, $rate - 1 , 1, true); //get the element base on the rate value, #1: json data. #2: offfset, #3: length, #4: preserve_keys
            $rateToBeUpdated = array_key_first($detected); //get the element key
            $currentJsonRate[$rateToBeUpdated] = $currentJsonRate[$rateToBeUpdated] + 1;

            $workerAggregatedRate = array(
                'company_id' => $companyID,
                'average_rate' => $this->computeAverage($currentJsonRate),
                'type' => 'loaning',
                'rates' => json_encode($currentJsonRate),
            );
            CompanyRatingAggregate::where('company_id', $companyID)
                ->where('type', 'loaning')
                ->update($workerAggregatedRate);
        }


        
    }

    public function checkIfCompanyAggregateExist($companyID, $type){
        return CompanyRatingAggregate::where('company_id', $companyID)
            ->where('type', $type)
            ->first();
    }

    public function computeAverage($newRateCount){
        /* 
            FORMULA USED
            1 -5 = ratings
            n = number of votes per rating
            sum = (1 * n) + (2 * n) +  (3 * n) +  (4 * n) +  (5 * n)
            avarage = sum / total number of votes
        */

        $sum = (1 * $newRateCount['rate_1']) + (2 * $newRateCount['rate_2']) +  (3 * $newRateCount['rate_3']) +  (4 * $newRateCount['rate_4']) +  (5 * $newRateCount['rate_5']);
        $totalVotes = $newRateCount['rate_1'] + $newRateCount['rate_2'] + $newRateCount['rate_3'] + $newRateCount['rate_4'] + $newRateCount['rate_5'];

        return $sum / $totalVotes;
    }
}
