<?php

namespace App\Classes\Modules\Companies\Services;


use App\Classes\General\Helper;
use App\Classes\Modules\Bookings\DataTransferObjects\CalculationObject;
use App\Classes\Modules\Companies\DataTransferObjects\CompanyServiceConfigurationsObject;
use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject;
use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Models\Company;
use App\Models\Currency;
use App\Models\ServiceType;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class FetchesCompanyServiceSettings
{


    /**
     * @param Company $company
     * @param CurrencyConversionObject $object
     * @return CompanyServiceConfigurationsObject
     */
    public function execute(Company $company, CurrencyConversionObject $object){
        /** @var ServiceType $service */
        $service = $company->services()->where('id', $object->getServiceId())->first();

        $constants= $service->constants()->whereIn('segment_id', $company->segments->pluck('id'))->get();

        $standardConfigurations = $constants->firstWhere('reference', SegmentConstants::SERVICE_TYPE);

        $rate = Currency::find($object->getCurrencyId())->rates->where('payment_method_type', $object->getPaymentMethod())
            ->where('service_id', $object->getServiceId())->first();

        $currency = collect($standardConfigurations->detail->currencies)->firstWhere('id','=', $object->getCurrencyId());

        $standardConfigurations = new CompanyServiceConfigurationsObject($standardConfigurations->detail->is_billable, $standardConfigurations->detail->bank_id, $standardConfigurations->detail->po_limit->value, $standardConfigurations->detail->tax->value,
            $standardConfigurations->detail->service_charge->value, $standardConfigurations->detail->minimum_charge->value,
            $currency->max_limit->value, $currency->min_limit->value, $rate->selling);

        if($this->hasCustomOptions($constants)){
            $customOptions = $this->getServiceCustomOptions($constants, $object, $standardConfigurations)->sortBy(function($option) use($object) {
                return (new CalculationObject($object, $option))->getTotal();
            });

            return $object->getType() === 0 ? $customOptions->last() : $customOptions->first();
        };

        return $standardConfigurations;
    }

    /**
     * @param $constants
     * @param CurrencyConversionObject $object
     * @param CompanyServiceConfigurationsObject $standardConfigurations
     * @return mixed
     */
    private function getServiceCustomOptions($constants, CurrencyConversionObject $object, CompanyServiceConfigurationsObject $standardConfigurations){
        return $constants->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->map(function($constant) use($object, $standardConfigurations) {

            $customOptions = clone $standardConfigurations;

            $methods = collect(Helper::getClassMethodsArray(CompanyServiceConfigurationsObject::class))->filter(function($value){ return substr( $value, 0, 3) === "get"; });

            $methods->map(function($methodName) use ($constant, $object, $customOptions) {
                $option = Helper::getPropertyName($methodName);

                $setMethod = 'set'.Str::studly($option);

                if(in_array($option, ['min_limit', 'max_limit', 'rate']) && !empty($constant->detail->currencies)) {

                    $currency = collect($constant->detail->currencies)->firstWhere('id','=', $object->getCurrencyId());

                    if($currency) {
                        if($option === 'rate') {
                            return $customOptions->$setMethod(collect($currency->rates)->firstWhere('payment_type','=', $object->getPaymentMethod())->selling->value);
                        }

                        return $customOptions->$setMethod($currency->$option->value);
                    }

                };

                if(property_exists($constant->detail, $option)) {

                    if($option === 'bank') return $customOptions->$setMethod($constant->detail->bank_id);

                    return $customOptions->$setMethod($constant->detail->$option->value);
                }
            });

            return $customOptions;

        });

    }

    private function hasCustomOptions(Collection $constants){
        return $constants->contains(function($value){
            return $value->reference === SegmentConstants::CUSTOM_SERVICE_TYPE;
        });
    }



}