<?php

namespace domain\_;

use yii\base\ErrorException;

abstract class AbstractService extends AbstractSingleton implements ServiceInterface
{
    use ProducerContextTrait;

    protected function getHierarchy(): array
    {
        return [
            DefinitionInterface::class,
            SolverInterface::class,
            RepositoryQueryInterface::class,
            RepositoryInterface::class,
            CheckerInterface::class,
            NotifierInterface::class,
            BuilderInterface::class,
            ResolverInterface::class,
            GeneratorInterface::class,
            ManagerInterface::class,
        ];
    }

    protected function loadService(string $serviceClass)
    {
        if(!$this->respectHierarchy($serviceClass)) {
            throw new ErrorException('Le service '.$serviceClass.' ne peut pas être chargé ici.');
        }

        return $serviceClass::getInstance();
    }

    protected function loadDependencies(): void
    {
    }

    protected function respectHierarchy(string $serviceClassAsked): bool
    {
        $domain = \Yii::$app->logic;
        $serviceCurrentClass = get_class($this);
        $levelHierarchyServiceAsked = $this->getServiceLevelHierarchy($serviceClassAsked);
        $levelHierarchyServiceCurrent = $this->getServiceLevelHierarchy($serviceCurrentClass);

        if($levelHierarchyServiceAsked < $levelHierarchyServiceCurrent) {
            return true;
        }
        elseif($levelHierarchyServiceAsked == $levelHierarchyServiceCurrent
            && $domain->getModuleLevelHierarchyByService($serviceClassAsked)
                < $domain->getModuleLevelHierarchyByService($serviceCurrentClass)) {

            return true;
        }

        return false;
    }

    protected function getServiceLevelHierarchy(string $serviceClass): int
    {
        $hierarchyArray = $this->getHierarchy();

        foreach($hierarchyArray as $key => $interface) {
            if($this->classImplementsInterface($interface, $serviceClass)) {
                return $key;
            }
        }

        throw new ErrorException('Service introuvable dans la hiérarchie. Attention à bien ajouter 
            FactoryInterface, SolverInterface ou BuilderInterface au service.');
    }

    protected function classImplementsInterface(string $interface, $object = null)
    {
        if(is_null($object)) {
            $object = $this;
        }

        return in_array($interface, class_implements($object));
    }
}