<?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 ProductImportReader implements
    \ItemReaderInterface,
    \StepExecutionAwareInterface,
    \FlushableInterface
{
   

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

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

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

    protected $connectorService;

    protected $data = [];

    protected $startCount = 0;

    protected $page = 1;
    
    const ACTION_GET_PRODUCT = "getAllProduct";
    const ACTION_GET_PRODUCT_BY_PAGE = "getAllProductByPage";
    const ACTION_GET_VARIATION = "getVariation";
    const ACTION_GET_VARIANTION_BY_ID = "getVariationById";
    const RESULT_COUNT = 11;
    const RESULT_COUNT_WITHOUT_CODE = 10;


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

    protected function getProductData()
    {
        $getProduct = [];
        $params = $this->stepExecution->getJobParameters()->all();
        $exportProfile = (isset($params['exportProfile'])) ? $params['exportProfile'] : "";
        while (empty($getProduct)) {
            $result = $this->connectorService->requestApiAction(
                self::ACTION_GET_PRODUCT_BY_PAGE,
                [],
                ["page" => $this->page, "exportProfile" => $exportProfile]
            );

            if (count($result) <= 1) {
                return null;
            }
            
            $getProduct = $this->format($result,$exportProfile);
            
            $this->page++;

            if (!empty($getProduct)) {
                return $getProduct;
            }
        }

        return null;
    }

    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) {
            $products = $this->getProductData();
            
            if ($products) {
                $this->data = $products;
            } 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($this->data->current(), $e);
            }

            return $item;
        }
    }

    
    public function format($results,$exportProfile)
    {
        $productdata = [];
        $params = $this->stepExecution->getJobParameters()->all();
        $locale = $params['filters']['structure']['locale'];
        $mapProduct = $this->connectorService->getAllProductCodeByEntity('product') !== null ?
        $this->connectorService->getAllProductCodeByEntity('product') : [];
        if(isset($results['code'])) {
            unset($results['code']);
        }
        foreach ($results as $result) {
           
            if (!empty($result['variations'])) {
                $attributes = $result['attributes'];
                $name = [];
                $code = '';
                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');
                $parent = $result['sku'];
                $category = $this->getCategory($result['categories']);
                
                if (!empty($name)) {
                    sort($name);
                }

                $oldProductModel = $this->connectorService->getProductModelFamilyVariant()->findOneByIdentifier($result['sku']);
                $family = $oldProductModel ? $oldProductModel->getFamily()->getCode() : "WooCommerce";
                $family_variant = $oldProductModel ? $oldProductModel->getFamilyVariant()->getCode() : "woocommerce_".implode("_", $name);
                $attrCodes = $this->connectorService->getVariantAttrCode($family_variant);
                //$attrCodes = $this->connectorService->getFamilyVariantAttributes($family_variant);
               

                $parentId = $result['id'];
                foreach ($result['variations'] as $variationId) {
                    $varresult = $this->connectorService->requestApiAction(
                        self::ACTION_GET_VARIANTION_BY_ID,
                        [],
                        ["product" => $parentId,"exportProfile"=>$exportProfile]
                    );
                    
                    if ($varresult['code'] == '200') {
                        unset($varresult['code']);

                        $identifier = $parent.'_'.$variationId;
                        
                        
                        
                        if (empty($identifier)) {
                            
                            $this->stepExecution->addWarning('The identfier does not exist in WooCommerce Product '.$varresult['sku'].'. at line '.__LINE__, [], new \DataInvalidItem([$varresult['sku']]));
                            continue;
                        }
                       
                        $attr = $varresult['attributes'];
                                            
                        if (empty($attr)) {
                            $this->stepExecution->addWarning('Attribute not Found For Product '.$varresult['sku'].'. at line '.__LINE__, [], new \DataInvalidItem([$varresult['sku']]));
                            continue;
                        }

                        
                        
                        $productIdData =[
                                            'sku' => $identifier,
                                            'enabled' => 1,
                                            'family' => $family,
                                            'parent' => $parent
                                        ];

                        foreach ($attr as $attrValue) {
                            $name = $this->connectorService->convertToCode($attrValue['name']);
                            $name = $this->connectorService->getAttributeCode($name);
                            $value = $this->connectorService->getAttributeOptionCode($name, $attrValue['option']);
                            $value = $this->connectorService->convertToCode($value);
                            
                            if ($value) {
                                $productIdData[$name] = $value;
                            }
                        }
                        
                        $productAttrData = $this->getOtherProductData($mapped, $varresult, $attrCodes);
                        if ($varresult['image']) {
                            $variantsimages[] = $varresult['image'];
                            
                            $images = $this->getImages($variantsimages, $attrCodes);
                            $productdata[]=array_filter(array_merge($productIdData, $productAttrData, $images));
                        } else {
                            $productdata[]=array_filter(array_merge($productIdData, $productAttrData));
                        }
                    }
                }
            } else {
                $mapped = $this->connectorService->getMultiSetting('settings');
                $code = $result['sku'];
                
                $category = $this->getCategory($result['categories']);
                
                $oldProduct = $this->connectorService->getProductFamily()->findOneByIdentifier($result['sku']);
               
                $family = $oldProduct && $oldProduct->getFamily() ? $oldProduct->getFamily()->getCode() : "WooCommerce";
                
                
                $attrCodes = $this->connectorService->getAttributeByFamily($family);
                
                $customAttrsCodes = $this->getCustomAttributes($result['attributes'], $locale);
                
                if ($code == '') {
                  
                    $this->stepExecution->addWarning('The identifier does not exist in WooCommerce Product . at line '.__LINE__, [], new \DataInvalidItem([$results]));
                    continue;
                }

                $productIdData = [
                                    'sku' => $code,
                                    'enabled' => 1,
                                    'family' => $family,
                                    'attributes' => [],
                                ];
                
                if ($category && $category != 'uncategorized') {
                    $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);
                    $productdata[]=array_filter(array_merge($productIdData, $productAttrData, $images));
                } else {
                    $productdata[]=array_filter(array_merge($productIdData, $productAttrData));
                }
            }
        }

        
        return $productdata;
    }


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

        return $attributes;
    }



    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 getCategory($categoryArray)
    {
        $category = [];
        $categories = '';
        if (is_array($categoryArray)) {
            foreach ($categoryArray as $categoryData) {
                $category[] = $this->connectorService->convertToCode($categoryData['slug']);
            }
            $categories = implode(",", $category);
        }
        
        return $categories;
    }

    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;
            }
        }

        $imagesValue = [];
        $existMediaAttr = array_reverse($existMediaAttr);
        
        if (count($existMediaAttr) == count($images)) {
            $imageData = array_combine($existMediaAttr, $images);
            $imagesValue = $this->mediaPathTransformer->transform($imageData, "/tmp");
        } elseif (count($existMediaAttr) > count($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);
    }
}
