<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magento\ConfigurableProduct\Plugin\Model\Attribute\Backend;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend;
use Magento\Framework\DataObject;

/**
 * Skip validate attributes used for create configurable product
 */
class AttributeValidation
{
    /**
     * @var Configurable
     */
    private $configurableProductType;

    /**
     * @param Configurable $configurableProductType
     */
    public function __construct(
        Configurable $configurableProductType
    ) {
        $this->configurableProductType = $configurableProductType;
    }

    /**
     * Verify is attribute used for configurable product creation and should not be validated.
     *
     * @param AbstractBackend $subject
     * @param \Closure $proceed
     * @param DataObject $entity
     * @return bool
     */
    public function aroundValidate(
        AbstractBackend $subject,
        \Closure $proceed,
        DataObject $entity
    ) {
        $attribute = $subject->getAttribute();
        if ($this->isAttributeShouldNotBeValidated($entity, $attribute)) {
            return true;
        }
        return $proceed($entity);
    }

    /**
     * Verify if attribute is a part of configurable product and should not be validated.
     *
     * @param DataObject $entity
     * @param AbstractAttribute $attribute
     * @return bool
     */
    private function isAttributeShouldNotBeValidated(DataObject $entity, AbstractAttribute $attribute): bool
    {
        if (!($entity instanceof ProductInterface && $entity->getTypeId() === Configurable::TYPE_CODE)) {
            return false;
        }
        $attributeId = $attribute->getAttributeId();
        $options = $entity->getConfigurableProductOptions() ?: [];
        $configurableAttributeIds = array_column($options, 'attribute_id');

        return in_array($attributeId, $configurableAttributeIds)
            || in_array($attributeId, $this->configurableProductType->getUsedProductAttributeIds($entity), true);
    }
}
