<?php

namespace Webkul\WooCommerceBundle\Connector\Processor;

use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Webkul\WooCommerceBundle\Listener\ClassDefinationForCompatibility;

$obj = new ClassDefinationForCompatibility();
$obj->objectCreate();

/**
 * Product processor to process and normalize entities to the standard format
 *
 * @author    Webkul Software Pvt Ltd 
 * @copyright  Webkul Software Pvt Ltd (https://www.webkul.com)
 */
class ProductProcessor implements \ItemProcessorInterface, \StepExecutionAwareInterface
{
    /** @var NormalizerInterface */
    protected $normalizer;

    /** @var \ChannelRepositoryInterface */
    protected $channelRepository;

    /** @var \AttributeRepositoryInterface */
    protected $attributeRepository;

    /** @var \ObjectDetacherInterface */
    protected $detacher;

    /** @var StepExecution */
    protected $stepExecution;

    /** @var \BulkMediaFetcher */
    protected $mediaFetcher;

    /** @var \EntityWithFamilyValuesFillerInterface */
    protected $productValuesFiller;

    /**
     * @param NormalizerInterface                   $normalizer
     * @param \ChannelRepositoryInterface            $channelRepository
     * @param \AttributeRepositoryInterface          $attributeRepository
     * @param \ObjectDetacherInterface               $detacher
     * @param \BulkMediaFetcher                      $mediaFetcher
     * @param \EntityWithFamilyValuesFillerInterface $productValuesFiller
     */
    public function __construct(
        NormalizerInterface $normalizer,
        \ChannelRepositoryInterface $channelRepository,
        \AttributeRepositoryInterface $attributeRepository,
        \ObjectDetacherInterface $detacher,
        \BulkMediaFetcher $mediaFetcher,
        \EntityWithFamilyValuesFillerInterface $productValuesFiller
    ) {
        $this->normalizer = $normalizer;
        $this->detacher = $detacher;
        $this->channelRepository = $channelRepository;
        $this->attributeRepository = $attributeRepository;
        $this->mediaFetcher = $mediaFetcher;
        $this->productValuesFiller = $productValuesFiller;
    }

    /**
     * {@inheritdoc}
     */
    public function process($product)
    {
        if (! $product instanceof \ProductInterface) {
            $this->stepExecution->incrementSummaryInfo('read', -1);
            return;
        }
        
        $parameters = $this->stepExecution->getJobParameters();
        if ($this->stepExecution->getJobExecution()->getJobInstance()->getJobName() != 'prestashop_quick_export') {
            $structure = $parameters->get('filters')['structure'];
            $channel = $this->channelRepository->findOneByIdentifier($structure['scope']);
            
            if (method_exists($this->productValuesFiller, 'fillMissingValues')) {
                $this->productValuesFiller->fillMissingValues($product);
            }

            $productStandard = $this->normalizer->normalize($product, 'standard', [
                'channels' => [$channel->getCode()],
                'locales'  => array_intersect(
                    $channel->getLocaleCodes(),
                    $parameters->get('filters')['structure']['locales']
                ),
            ]);

        // if (!(method_exists($this->productValuesFiller, 'fillMissingValues'))) {
            //     $this->productValuesFiller->fromStandardFormat($productStandard);
            // }
        } else {
            $channel = $this->channelRepository->findOneByIdentifier($parameters->get('scope'));
            if (method_exists($this->productValuesFiller, 'fillMissingValues')) {
                $this->productValuesFiller->fillMissingValues($product);
            }

            $productStandard = $this->normalizer->normalize($product, 'standard', [
                'channels' => [$channel->getCode()],
                'locales'  => $channel->getLocaleCodes(),
            ]);
        }


        //////////////////////Custom code////////////////////
        $variantAttributes = $attributes = [];
        $allVariantAttributes = [];
        if ($productStandard['parent']) {
            $parent = $product->getParent();
            $levelCount = 0;
            foreach ($parent->getFamilyVariant()->getVariantAttributeSets() as $variantAttributeSet) {
                $levelCount++;
                foreach ($variantAttributeSet->getAxes() as $axes) {
                    $variantAttributes[] = $axes->getCode();
                }
            }

            if ($levelCount == 2) {
                $productStandard['parent'] = $parent->getParent()->getCode();
            }

            foreach ($product->getFamilyVariant()->getAttributes() as $attribute) {
                $attributes[] = $attribute->getCode();
            }
            
            $allVariantAttributes  = $this->getVariantAttributes($product);
        }
        $productStandard['attributes'] = $attributes;
        $productStandard['variantAttributes'] = $variantAttributes;
        $productStandard['allVariantAttributes'] = $allVariantAttributes;
        
        //////////////////////Custom code////////////////////


        if ($this->areAttributesToFilter($parameters)) {
            $attributesToFilter = $this->getAttributesToFilter($parameters);
            $productStandard['values'] = $this->filterValues($productStandard['values'], $attributesToFilter);
        }

        if ($parameters->has('with_media') && $parameters->get('with_media')) {
            $directory = $this->stepExecution->getJobExecution()->getExecutionContext()
                ->get(\JobInterface::WORKING_DIRECTORY_PARAMETER);

            $this->fetchMedia($product, $directory);
        } else {
            $mediaAttributes = $this->attributeRepository->findMediaAttributeCodes();
            $productStandard['values'] = array_filter(
                $productStandard['values'],
                function ($attributeCode) use ($mediaAttributes) {
                    return !in_array($attributeCode, $mediaAttributes);
                },
                ARRAY_FILTER_USE_KEY
            );
        }

        $this->detacher->detach($product);

   
        return $productStandard;
    }

    /**
     * {@inheritdoc}
     */
    public function setStepExecution(\StepExecution $stepExecution)
    {
        $this->stepExecution = $stepExecution;
    }

    /**
     * Fetch medias on the local filesystem
     *
     * @param ProductInterface $product
     * @param string           $directory
     */
    protected function fetchMedia(\ProductInterface $product, $directory)
    {
        $identifier = $product->getIdentifier();
        $this->mediaFetcher->fetchAll($product->getValues(), $directory, $identifier);

        foreach ($this->mediaFetcher->getErrors() as $error) {
            $this->stepExecution->addWarning($error['message'], [], new \DataInvalidItem($error['media']));
        }
    }

    /**
     * Filters the attributes that have to be exported based on a product and a list of attributes
     *
     * @param array $values
     * @param array $attributesToFilter
     *
     * @return array
     */
    protected function filterValues(array $values, array $attributesToFilter)
    {
        $valuesToExport = [];
        $attributesToFilter = array_flip($attributesToFilter);
        foreach ($values as $code => $value) {
            if (isset($attributesToFilter[$code])) {
                $valuesToExport[$code] = $value;
            }
        }

        return $valuesToExport;
    }

    /**
     * Return a list of attributes to export
     *
     * @param JobParameters $parameters
     *
     * @return array
     */
    protected function getAttributesToFilter(\JobParameters $parameters)
    {
        $attributes = $parameters->get('filters')['structure']['attributes'];
        $identifierCode = $this->attributeRepository->getIdentifierCode();
        if (!in_array($identifierCode, $attributes)) {
            $attributes[] = $identifierCode;
        }

        return $attributes;
    }

    /**
     * Are there attributes to filters ?
     *
     * @param JobParameters $parameters
     *
     * @return bool
     */
    protected function areAttributesToFilter(\JobParameters $parameters)
    {
        return isset($parameters->get('filters')['structure']['attributes'])
            && !empty($parameters->get('filters')['structure']['attributes']);
    }

    /* get variant attributes of product */
    protected function getVariantAttributes($product)
    {
        $result = [];
        $varAttributeSets = $product->getFamilyVariant()->getVariantAttributeSets();
        foreach ($varAttributeSets as $attrSet) {
            $axises = $attrSet->getAttributes();

            foreach ($axises as $axis) {
                $result[] = $axis->getCode();
            }
        }

        return $result;
    }
}

