<?php

namespace App\Modules\CategoryProvider\Application\Update;

use App\Modules\CategoryProvider\Application\Index\CategoryProviderIndexer;
use App\Modules\CategoryProvider\Domain\CategoryProvider;
use App\Modules\CategoryProvider\Domain\CategoryProviderAbrv;
use App\Modules\CategoryProvider\Domain\CategoryProviderLevel;
use App\Modules\CategoryProvider\Domain\CategoryProviderName;
use App\Modules\CategoryProvider\Domain\CategoryProviderStatus;
use App\Modules\CategoryProvider\Domain\IdCategoryProvider;
use App\Modules\Shared\Domain\Aggregate\AggregateRoot;
use App\Modules\Shared\Domain\Bus\Query\QueryHandler;
use App\Modules\TypeProvider\Domain\IdTypeProvider;
use App\Modules\Versioner\Application\Check\VersionChecker;
use App\Modules\CategoryProvider\Application\FindNextLevel\CategoryProviderNextLevelFinder;

final class UpdateCategoryProviderQueryHandler implements QueryHandler
{
    public function __construct(
        private CategoryProviderIndexer $indexer,
        private CategoryProviderUpdater $updater,
        private VersionChecker $versionChecker,
        private CategoryProviderNextLevelFinder $nextLevelFinder
    ) {}

    private function conditionalSet($condition, AggregateRoot &$aggregateRoot, $setter, $object)
    {
        if (isset($condition)) {
            $aggregateRoot->$setter(new $object($condition));
        }
    }

    public function __invoke(UpdateCategoryProviderQuery $query): UpdateCategoryProviderResponse
    {
        /** @var CategoryProvider $index */
        $index = $this->indexer->__invoke(new IdCategoryProvider($query->id));
        $level = $this->nextLevelFinder->__invoke($index->idTypeProvider());
        $oldLevel = $index->level();
        $this->versionChecker->__invoke($index, $query->version);

        $set = [
            [$query->name, $index, 'setName', CategoryProviderName::class],
            [$query->abrv, $index, 'setAbrv', CategoryProviderAbrv::class],
            [max($query->level, $level->value() - 1), $index, 'setLevel', CategoryProviderLevel::class],
            [$query->status, $index, 'setStatus', CategoryProviderStatus::class],
            [$query->idTypeProvider, $index, 'setIdTypeProvider', IdTypeProvider::class],
        ];

        foreach ($set as $value) {
            $this->conditionalSet($value[0], $value[1], $value[2], $value[3]);
        }

        return new UpdateCategoryProviderResponse(
            $this->updater->__invoke($index, $oldLevel, $query->idAdmin)
        );
    }
}
