<?php

namespace Webkul\WooCommerceBundle\Connector\Reader\Import;

use Webkul\WooCommerceBundle\Services\WooCommerceConnector;
use Webkul\WooCommerceBundle\Services\MediaPathTransformer;
use Webkul\WooCommerceBundle\Listener\ClassDefinationForCompatibility;

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

class ProductModelImportReader implements
    \ItemReaderInterface,
    \StepExecutionAwareInterface,
    \FlushableInterface
{
   

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

    /** @var \ArrayConverterInterface */
    protected $converter;

    /** @var MediaPathTransformer */
    protected $mediaPathTransformer;

    protected $connectorService;

    protected $data = [];
    protected $startCount = 0;
    protected $categoryCodes = null;
    protected $page = 1;

    const ACTION_GET_VARIABLE_PRODUCT = "getAllVariableProductByPage";
    const RESULT_COUNT = 11;
    
    /**
     * @param \ArrayConverterInterface $converter
     */
    public function __construct(\ArrayConverterInterface $converter, WooCommerceConnector $connectorService, MediaPathTransformer $mediaPathTransformer)
    {
        $this->converter = $converter;
        $this->connectorService = $connectorService;
        $this->mediaPathTransformer = $mediaPathTransformer;
    }

    protected function getAllProductModel()
    {
        $params = $this->stepExecution->getJobParameters()->all();
        $exportProfile = (isset($params['exportProfile'])) ? $params['exportProfile'] : "";
        $familyVariant = [];
        while (empty($familyVariant)) {
            $result = $this->connectorService->requestApiAction(
                self::ACTION_GET_VARIABLE_PRODUCT,
                [],
                ["page" => $this->page, "type" => "variable", "exportProfile" => $exportProfile]
            );
            
            if (count($result) <= 1) {
                return null;
            }
            $getProductModel = $this->format($result);
            $this->page++;

            if ($getProductModel) {
                return $getProductModel;
            }
        }
    }

    public function read()
    {
        $mapped = $this->connectorService->getMultiSetting('settings');
        if (empty($mapped)) {
            $this->stepExecution->addWarning("Please do the mapping in setting.", [], new \DataInvalidItem([json_encode([])]));
            $this->stepExecution->setTerminateOnly();
        }
        
        if (current($this->data) == false) {
            $productModels = $this->getAllProductModel();
            
            if ($productModels) {
                $this->data = $productModels;
            } else {
                return null;
            }
        }

        if ($data = current($this->data)) {
            $item = [];
            foreach ($data as $attributeName => $attributeValue) {
                $item[$attributeName] = $attributeValue;
            }

            next($this->data);

            if (null !== $this->stepExecution) {
                $this->stepExecution->incrementSummaryInfo('item_position');
            }
            
            try {
                $item = $this->converter->convert($item);
            } catch (\DataArrayConversionException $e) {
                $this->skipItemFromConversionException(current($this->data), $e);
            }

            return $item;
        }
    }

    public function format($results)
    {
        $productModel = [];

        $params = $this->stepExecution->getJobParameters()->all();
        $locale = $params['filters']['structure']['locale'];
        
        if (is_array($locale)) {
            $locale = reset($locale);
        }

        foreach ($results as $result) {
            if (!empty($result['variations'])) {
                $attributes = $result['attributes'];
                $name = [];
                foreach ($attributes as $attribute) {
                    if ($attribute['variation']) {
                        $code = $this->connectorService->convertToCode($attribute['name']);
                        $checkAttr = $this->checkExistAttr($code);

                        if ($checkAttr) {
                            $name[] = $checkAttr;
                        }
                    }
                }
    
                $mapped = $this->connectorService->getMultiSetting('settings');
                $codes = $this->connectorService->getAttributeCodes('pim_catalog_price_collection');
                
                $priceAttr = [];
                foreach ($mapped as $map) {
                    if (in_array($map, $codes)) {
                        $priceAttr[] = $map;
                    }
                }
                
                if (!empty($name)) {
                    sort($name);
                    
                    $oldProductModel = $this->connectorService->getProductModelFamilyVariant()->findOneByIdentifier($result['sku']);
                    $family_variant = $oldProductModel ? $oldProductModel->getFamilyVariant()->getCode() : "woocommerce_".implode("_", $name);
                   
                
                    $attrCodes = $this->connectorService->getFamilyVariantAttributes($family_variant);
                    $code = $result['sku'];
                    $customAttrsCodes = $this->getCustomAttributes($result['attributes'], $locale);
                    
                    $category = $this->getCategory($result['categories']);
                    $category = $category && $category !== 'uncategorized' ?  $category : null;
                    $productIdData =[
                                        'code' => $code,
                                        'family_variant' => $family_variant
                                    ];
                    if ($category) {
                        $productIdData['categories'] =  $category;
                    }
                    

                    foreach ($customAttrsCodes as $customAttrCode => $customAttrLabel) {
                        if ($customAttrCode && '' !== $customAttrCode) {
                            $mapped[$customAttrCode] = $customAttrLabel;
                        }
                    }

                    $productAttrData = $this->getOtherProductData($mapped, $result, $attrCodes);
                    
                    if ($result['images']) {
                        $images = $this->getImages($result['images'], $attrCodes);
                        $productModel[] = array_merge($productIdData, $productAttrData, $images);
                    } else {
                        $productModel[] = array_merge($productIdData, $productAttrData);
                    }
                }
            }
        }

        return $productModel;
    }


    public function getCustomAttributes($attributeArray, $locale)
    {
        
        $attributes = [];
        foreach ($attributeArray as $attributeData) {
            $label = $attributeData['name'];
            $code = $this->connectorService->getAttributeCodeByLabel($label, $locale);
            if ($code) {
                $attributes[$code] = $label;
            }
        }

        return $attributes;
    }

    public function getCategory($categoryArray)
    {
        $category = [];
        if (!$this->categoryCodes) {
            $this->categoryCodes = $this->connectorService->getCategoryiesCodes();
        }

        foreach ($categoryArray as $categoryData) {
            $slug = $this->connectorService->convertToCode($categoryData['slug']);
            $category[] = in_array($slug, $this->categoryCodes) ? $slug : null;
        }
        $categories = implode(",", $category);
        
        return $categories;
    }

    public function getOtherProductData($maps, $result, $attrCodes = null)
    {
        $product = [];
        if ($attrCodes) {
            $params = $this->stepExecution->getJobParameters()->all();
            $localeCodes = $params['filters']['structure']['locales'];
            $currency = $params['filters']['structure']['currency'];
            $scope = $params['filters']['structure']['scope'];
            $locale = $params['filters']['structure']['locale'];
    
            if (is_array($locale)) {
                $locale = reset($locale);
            }
            $priceCollection = $this->connectorService->getAttributeCodes('pim_catalog_price_collection');
            $metricCollection = $this->connectorService->getAttributeCodes('pim_catalog_metric');
            
            $mapping = [];
            foreach ($attrCodes as $codes) {
                $attributeCode = isset($maps[$codes]) ? $maps[$codes] : null;
                if ($attributeCode) {
                    $mapping[$codes] = $attributeCode;
                }
            }
    

            $customAttributesNames = [];
            $flipedMapping = array_flip($maps);
            if (isset($result['attributes'])) {
                foreach ($result['attributes'] as $attribute) {
                    if (isset($attribute['options'])) {
                        foreach ($attribute['options'] as $option) {
                            $attrName = $attribute['name'];
                            if (isset($flipedMapping[$attrName])) {
                                $optionCode = $this->connectorService->getAttributeOptionCodeByLabel($option, $flipedMapping[$attrName], $locale);
                                if ($optionCode) {
                                    $customAttributesNames[$attribute['name']][] = $optionCode;
                                }
                            }
                        }
                    }
                }
            }

            foreach ($mapping as $mapAttr => $mapValue) {
                $checklocale=   $this->connectorService->checkLocale($mapAttr);
                $checkscope = $this->connectorService->checkScope($mapAttr);
                $checkPrice = in_array($mapAttr, $priceCollection);
                $checkMetric = in_array($mapAttr, $metricCollection);
                
                $attrType = $this->connectorService->getAttrTypeByCode($mapAttr);
                
                if ($checklocale) {
                    $mapAttr .= '-'.$locale;
                }
                
                if ($checkscope) {
                    $mapAttr .= '-'.$scope;
                }
                
                if ($checkPrice) {
                    $mapAttr .= '-'.$currency;
                }

                if (isset($result[$mapValue])  || isset($result['dimensions'][$mapValue])) {
                    if ($checkMetric) {
                        $unit = $this->connectorService->getDefaultUnit($mapAttr);
                        $product[$mapAttr] = isset($result[$mapValue]) ?
                                                        $result[$mapValue] :
                                                        (isset($result['dimensions'][$mapValue]) ?
                                                        $result['dimensions'][$mapValue] :
                                                        null) ;
                        if($product[$mapAttr]) {
                            $mapAttr .= '-'.'unit';
                            $product[$mapAttr] = $unit ? $unit : null;
                        }
                    } elseif (in_array($mapValue, ['length', 'height', 'width'])) {
                        $product[$mapAttr] = $result['dimensions'][$mapValue];
                    } else {
                        $product[$mapAttr] = str_replace("\n", "", strip_tags($result[$mapValue]));
                    }
                }


                if (isset($customAttributesNames[$mapValue])) {
                    if ($attrType[0]['type'] == 'pim_catalog_simpleselect') {
                        $product[$mapAttr] = reset($customAttributesNames[$mapValue]);
                    } elseif ($attrType[0]['type'] == 'pim_catalog_multiselect') {
                        $product[$mapAttr] = implode(',', $customAttributesNames[$mapValue]);
                    } elseif ($attrType[0]['type'] == 'pim_catalog_text') {
                        $product[$mapAttr] = $customAttributesNames[$mapValue];
                    }

                }
            }
        }
        return $product;
    }

    public function checkExistAttr($key)
    {
        $codes = $this->connectorService->getAttributeCodes('pim_catalog_simpleselect');
        
        foreach ($codes as $code) {
            if (strtolower($key) == strtolower($code)) {
                return $code;
            }
        }

        return null;
    }

    public function getImages($images, $attrCodes)
    {
        $mediaAttrs = $this->connectorService->getAttributeCodes('pim_catalog_image');
        $existMediaAttr = [];
        foreach ($mediaAttrs as $mediaAttr) {
            if (in_array($mediaAttr, $attrCodes)) {
                $existMediaAttr[] = $mediaAttr;
            }
        }
        $imageValue = [];
        $existMediaAttr = array_reverse($existMediaAttr);
        
        if (count($existMediaAttr) == count($images)) {
            $imageData = array_combine($existMediaAttr, $images);
            $imagesValue = $this->mediaPathTransformer->transform($imageData, "/tmp");
        } elseif ($existMediaAttr > $images) {
            $sliceCount = count($existMediaAttr) - count($images);
            $existMediaAttr = array_slice($existMediaAttr, $sliceCount);
            $imageData = array_combine($existMediaAttr, $images);
            $imagesValue = $this->mediaPathTransformer->transform($imageData, "/tmp");
        } else {
            $sliceCount = count($images) - count($existMediaAttr);
            $images = array_slice($images, $sliceCount);
            $imageData = array_combine($existMediaAttr, $images);
            $imagesValue = $this->mediaPathTransformer->transform($imageData, "/tmp");
        }
        
        return $imagesValue;
    }

    /**
     * {@inheritdoc}
     */
    public function flush()
    {
        $this->xml = null;
    }

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

    /**
     * @param array                        $item
     * @param \DataArrayConversionException $exception
     *
     * @throws \InvalidItemException
     * @throws \InvalidItemFromViolationsException
     */
    protected function skipItemFromConversionException(array $item, \DataArrayConversionException $exception)
    {
        if (null !== $this->stepExecution) {
            $this->stepExecution->incrementSummaryInfo('skip');
        }

        if (null !== $exception->getViolations()) {
            throw new \InvalidItemFromViolationsException(
                $exception->getViolations(),
                new \FileInvalidItem($item, $this->stepExecution->getSummaryInfo('item_position')),
                [],
                0,
                $exception
            );
        }

        $invalidItem = new \FileInvalidItem(
            $item,
            $this->stepExecution->getSummaryInfo('item_position')
        );

        throw new \InvalidItemException($exception->getMessage(), $invalidItem, [], 0, $exception);
    }
}
