<?php
/**
 * Copyright 2020 Adobe
 * All Rights Reserved.
 *
 * NOTICE: Adobe permits you to use, modify, and distribute this file in
 * accordance with the terms of the Adobe license agreement accompanying
 * it.
 */
declare(strict_types=1);

namespace Magento\Mray\Api;

use Magento\Mray\Api\Data\CustomProjectIndexResult;
use Magento\Mray\CodeStructuralElement\Php\Reflection\Context\StructuralElementDeclarations;
use Magento\Mray\Index\GetMagentoNamespaces;
use Magento\Mray\Index\IsCoreDependency;
use Magento\Mray\Index\MagentoApiIndexAdapter;
use Magento\Mray\Index\Scanner\Tuner;
use Magento\Mray\Index\Traverser;
use Magento\Mray\Index\Traverser\PhpCodeUsageFilter\CustomProjectCodeUsageFilter;
use Magento\Mray\MagentoApiIndex\Api;
use Magento\Mray\Package\AbstractTree\Node\Node;

class CustomProjectIndex
{
    /**
     * @param string $path
     * @param string $version
     * @return CustomProjectIndexResult
     */
    public function execute(
        string $path,
        string $version
    ): CustomProjectIndexResult {
        $phpElementsRegistry = new StructuralElementDeclarations();
        $isCoreDependency = new IsCoreDependency(new GetMagentoNamespaces());

        $versionIndex = (new Api())->getApiIndex($version);
        $phpElementsRegistry->withKnowledge(new MagentoApiIndexAdapter($versionIndex));
        $indexEngine = new MagentoIndexEngine(
            [
                new Tuner\MagentoComposerDistribution(),
                new Tuner\MagentoCustomCodeFilter($version),
                new Tuner\PackagePathAttributeSetter(),
                new Tuner\MagentoPhpCodeNodeSetter(new Tuner\Filter\MagentoAssets()),
                new Tuner\DiXmlNodeSetter(),
                new Tuner\DbSchemaNodeSetter(),
                new Tuner\PhpCodeDeclaresAttributeSetter($phpElementsRegistry),
            ],
            [
                new Traverser\PhpCodeRuntimeTypesEstimation($phpElementsRegistry),
                new Traverser\PhpCodeUsageDiscovery(
                    $phpElementsRegistry,
                    new CustomProjectCodeUsageFilter($isCoreDependency),
                    $versionIndex
                ),
                new Traverser\DiXmlUsageDiscovery($versionIndex, $isCoreDependency),
                new Traverser\DbSchemaUsageDiscovery($version)
            ]
        );

        $index = $indexEngine->index($path);

        return new CustomProjectIndexResult($version, $this->getCustomizations($index));
    }

    /**
     * @param Node|[] $index
     * @return array
     */
    private function getCustomizations($index): array
    {
        $formatter = new Traverser\Formatter();
        (new Traverser\VisitingTraverser([$formatter]))->traverse($index);
        return $formatter->getOutput();
    }
}
