<?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\Reflection\ConstantDeclaration;

use Magento\Mray\CodeStructuralElement\Php\NodeRuntimeTypeResolver\Memorized;
use Magento\Mray\CodeStructuralElement\Php\NodeRuntimeTypeResolver\Resolver;
use Magento\Mray\CodeStructuralElement\Php\NodeVisitor\PhpDocAst;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ClassConstantDeclaration;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ClassLikeDeclaration\Finder;
use Magento\Mray\CodeStructuralElement\Php\Reflection\ClassLikeMemberPhpDocInheritance;
use Magento\Mray\CodeStructuralElement\Php\Reflection\InCodeDeclaration;
use phpDocumentor\Reflection\Type;
use PhpParser\Node;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use function array_values;
use function sha1;
use function sprintf;

class ClassConst implements ClassConstantDeclaration, InCodeDeclaration
{
    use ClassLikeMemberPhpDocInheritance;

    /**
     * @var Node\Stmt\ClassConst
     */
    private $group;
    /**
     * @var Node\Const_
     */
    private $const;
    /**
     * @var string|null
     */
    private $classLikeName;

    /**
     * @var Memorized|Resolver
     */
    private $typeResolver;

    /**
     * @param Node\Stmt\ClassConst $group
     * @param Node\Const_ $const
     * @param string|null $classLikeName
     * @param Finder|null $inheritedDeclarationsFinder
     */
    public function __construct(
        Node\Stmt\ClassConst $group,
        Node\Const_ $const,
        ?string $classLikeName,
        ?Finder $inheritedDeclarationsFinder = null
    ) {
        $this->group = $group;
        $this->const = $const;

        $this->classLikeName = $classLikeName;

        $this->inheritedDeclarationsFinder = $inheritedDeclarationsFinder;

        $this->typeResolver = new Memorized();
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return (string)$this->const->name;
    }

    /**
     * @return string|null
     */
    public function getClassLikeName(): ?string
    {
        return $this->classLikeName;
    }

    /**
     * @return Type
     */
    public function getType(): Type
    {
        return $this->typeResolver->resolve($this->const->value);
    }

    /**
     * @return Type
     */
    public function getValueType(): Type
    {
        return $this->getType();
    }

    /**
     * @return bool
     */
    public function isPublic(): bool
    {
        return $this->group->isPublic();
    }

    /**
     * @return bool
     */
    public function isProtected(): bool
    {
        return $this->group->isProtected();
    }

    /**
     * @return bool
     */
    public function isPrivate(): bool
    {
        return $this->group->isPrivate();
    }

    /**
     * @return string|null
     */
    public function getImplementationChecksum(): ?string
    {
        return null;
        // phpcs:disable Squiz.PHP.NonExecutableCode
        $g = clone $this->group;
        foreach ($g->consts as $key => $const) {
            if ($const !== $this->const) {
                unset($g->consts[$key]);
            }
        }
        $g->consts = array_values($g->consts);

//        $dumper = new NodeDumper();
        return sprintf('v1:sha1:%s', sha1($dumper->dump($g)));
    }

    /**
     * @inheritDoc
     */
    public function getDeclarationNodes(): array
    {
        return [
            $this->group,
            $this->const,
        ];
    }

    /**
     * @return PhpDocNode|null
     */
    public function getPhpDoc(): ?PhpDocNode
    {
        return $this->getPhpDocWithResolvedInheritance(
            $this->group->getAttribute(PhpDocAst::PHP_DOC_COMMENT)
        );
    }
}
