<?php

namespace Src\Modules\JsonObjects\Infrastructure;

use Src\Modules\JsonObjects\Interfaces\Infrastructure\IFactory;
use Src\Modules\JsonObjects\Interfaces\IFactory as IModuleFactory;
use Src\Modules\JsonObjects\Infrastructure\ItemQuery;
use Src\Modules\JsonObjects\Interfaces\Infrastructure\IItemStorage;
use Src\Modules\JsonObjects\Infrastructure\ItemStorage;
use Src\Modules\JsonObjects\Interfaces\Infrastructure\IItemPersistLayer;
use Src\Modules\JsonObjects\Infrastructure\ItemPersistLayer;
use Src\Modules\JsonObjects\Interfaces\Infrastructure\IDirsStorage;
use Src\Modules\JsonObjects\Infrastructure\DirsStorage;
use Src\Modules\JsonObjects\Interfaces\Infrastructure\IDirsQuery;
use Src\Modules\JsonObjects\Infrastructure\DirsQuery;
use Src\Modules\JsonObjects\Interfaces\Infrastructure\IDirsPersistLayer;
use Src\Modules\JsonObjects\Infrastructure\DirsPersistLayer;

class Factory implements IFactory
{

    protected IModuleFactory $moduleFactory;

    protected ?IItemStorage $storage = null;

    protected ?IItemPersistLayer $persistLayer = null;

    protected ?IDirsStorage $dirsStorage = null;

    protected ?IDirsPersistLayer $dirsPersistLayer = null;

    protected array $conf;

    public function init(array $conf = []): void
    {
        $this->conf = [
            'itemQuery' => ItemQuery::class,
            'itemStorage' => ItemStorage::class,
            'itemPersistLayer' => ItemPersistLayer::class,
            'dirsStorage' => DirsStorage::class,
            'dirsQuery' => DirsQuery::class,
            'dirPersistLayer' => DirsPersistLayer::class,
        ];
        $this->conf = array_replace_recursive($this->conf, $conf);
    }

    public function setModuleFactory(IModuleFactory $factory)
    {
        $this->moduleFactory = $factory;
    }

    protected function createQuery(): ItemQuery
    {
        $query = new $this->conf['itemQuery'];
        $tableName = $this->moduleFactory->getSetting(IModuleFactory::OBJECTS_TABLE);
        $query->setTableName($tableName);
        return $query;
    }

    public function getStorage(): ItemStorage
    {
        if ($this->storage === null) {
            $this->storage = new $this->conf['itemStorage'];
            $query = $this->createQuery();
            $this->storage->setObjectsQuery($query);
            $dirsStorage = $this->getDirsStorage();
            $this->storage->setDirStorage($dirsStorage);
        }
        return $this->storage;
    }

    public function getPersistLayer(): ItemPersistLayer
    {
        if ($this->persistLayer === null) {
            $this->persistLayer = new $this->conf['itemPersistLayer'];
            $tableName = $this->moduleFactory->getSetting(IModuleFactory::OBJECTS_TABLE);
            $this->persistLayer->setTableName($tableName);
        }
        return $this->persistLayer;
    }

    public function createDirsQuery(): IDirsQuery
    {
        $query = new $this->conf['dirsQuery'];
        $tableName = $this->moduleFactory->getSetting(IModuleFactory::DIRS_TABLE);
        $query->setTableName($tableName);
        return $query;
    }

    public function getDirsStorage(): IDirsStorage
    {
        if ($this->dirsStorage === null) {
            $this->dirsStorage = new $this->conf['dirsStorage'];
            $query = $this->createDirsQuery();
            $this->dirsStorage->setQuery($query);
            $query = $this->createDirsQuery();
            $this->dirsStorage->setParentQuery($query);
        }
        return $this->dirsStorage;
    }

    public function getDirsPersistLayer(): IDirsPersistLayer
    {
        if ($this->dirsPersistLayer === null) {
            $this->dirsPersistLayer = new $this->conf['dirPersistLayer'];
            $tableName = $this->moduleFactory->getSetting(IModuleFactory::DIRS_TABLE);
            $this->dirsPersistLayer->setTableName($tableName);
        }
        return $this->dirsPersistLayer;
    }
}
