<?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\CodeStructuralElement\Php\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitor;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use function array_filter;
use function array_unshift;

class MagentoApiPropagation implements NodeVisitor
{
    /**
     * @inheritDoc
     */
    public function beforeTraverse(array $nodes)
    {
        return null;
    }

    /**
     * @inheritDoc
     */
    public function enterNode(Node $node)
    {
        return null;
    }

    /**
     * @inheritDoc
     */
    public function leaveNode(Node $node)
    {
        if (!$node instanceof Node\Stmt\ClassLike) {
            return null;
        }

        $phpDoc = $node->getAttribute(PhpDocAst::PHP_DOC_COMMENT);
        if (!$phpDoc) {
            return null;
        }

        /** @var PhpDocNode $phpDoc */
        $arrayApiTags = $phpDoc->getTagsByName('@api');
        $arraySinceTags = $phpDoc->getTagsByName('@since');
        $arrayDeprecatedTags = $phpDoc->getTagsByName('@deprecated');
        $arraySeeTags = $phpDoc->getTagsByName('@see');

        $apiTag = end($arrayApiTags);
        $apiSinceTag = end($arraySinceTags);
        $deprecatedTag = end($arrayDeprecatedTags);
        $seeTag = end($arraySeeTags);

        $apiMarkers = array_filter([
            $apiTag ?? null,
            $apiSinceTag ?? null,
            $deprecatedTag ?? null,
            $seeTag ?? null
        ]);

        if (empty($apiMarkers)) {
            return null;
        }

        foreach ($node->stmts as $memberNode) {
            if ($memberNode instanceof Node\Stmt\ClassConst ||
                $memberNode instanceof Node\Stmt\Property ||
                $memberNode instanceof Node\Stmt\ClassMethod
            ) {
                $memberPhpDoc = $memberNode->getAttribute(PhpDocAst::PHP_DOC_COMMENT);
                if (!$memberPhpDoc) {
                    $memberPhpDoc = new PhpDocNode([]);
                    $memberNode->setAttribute(PhpDocAst::PHP_DOC_COMMENT, $memberPhpDoc);
                }

                array_unshift($memberPhpDoc->children, ...$apiMarkers);
            }
        }

        return null;
    }

    /**
     * @inheritDoc
     */
    public function afterTraverse(array $nodes)
    {
        return null;
    }
}
