<?php

namespace Webkul\WebkulCsvImportBundle\Connector\Reader\Csv;

use Akeneo\Tool\Component\Connector\ArrayConverter\ArrayConverterInterface;
use Akeneo\Tool\Component\Connector\Reader\File\Csv\Reader;
use Akeneo\Tool\Component\Connector\Reader\File\FileIteratorFactory;
use Akeneo\Tool\Component\Connector\Reader\File\FileReaderInterface;
use Akeneo\Tool\Component\Connector\Reader\File\MediaPathTransformer;
use Webkul\WebkulCsvImportBundle\Services\WebkulCsvConnector;

class ProductReader extends Reader implements FileReaderInterface
{
    /** @var MediaPathTransformer */
    protected $mediaPathTransformer;

    public $connectorService;

    protected $templateStore = null;
    /**
     * @param FileIteratorFactory     $fileIteratorFactory
     * @param ArrayConverterInterface $converter
     * @param MediaPathTransformer    $mediaPathTransformer
     * @param WebkulCsvConnector      $connectorService
     * @param array                   $options
     */
    public function __construct(
        FileIteratorFactory $fileIteratorFactory,
        ArrayConverterInterface $converter,
        MediaPathTransformer $mediaPathTransformer,
        WebkulCsvConnector $connectorService,
        array $options = []
    ) {
        parent::__construct($fileIteratorFactory, $converter, $options);

        $this->mediaPathTransformer = $mediaPathTransformer;
        $this->connectorService     = $connectorService;
    }

    /**
     * {@inheritdoc}
     */
    public function read()
    {

        $transformedData = [];
        $productData = [];
        $this->connectorService->setStepExecution($this->stepExecution);
        $jobParameters = $this->stepExecution->getJobParameters();
        $allJobParameters       = $this->stepExecution->getJobParameters()->all();
        if(!$this->templateStore) {
            $template                     = $this->connectorService->getTemplateStore($allJobParameters['exportProfile']);
            $storeTemplateData            = json_decode($template->getRawValues(), true);
            $this->templateStore          = isset($storeTemplateData['csvImportMapping']) ? $storeTemplateData['csvImportMapping'] : [];
        }
        $filePath = $jobParameters->get('filePath');
        if (null === $this->fileIterator) {
            $delimiter = $jobParameters->get('delimiter');
            $enclosure = $jobParameters->get('enclosure');
            $defaultOptions = [
                'reader_options' => [
                    'fieldDelimiter' => $delimiter,
                    'fieldEnclosure' => $enclosure,
                ],
            ];
            $this->fileIterator = $this->fileIteratorFactory->create(
                $filePath,
                array_merge($defaultOptions, $this->options)
            );
            $this->fileIterator->rewind();
        }
        
        $this->fileIterator->next();
        
        if ($this->fileIterator->valid() && null !== $this->stepExecution) {
            $this->stepExecution->incrementSummaryInfo('item_position');
        }
        
        $productTypeField = isset($this->templateStore['extraMapping']['productTypeFieldName']) ? $this->templateStore['extraMapping']['productTypeFieldName'] : '';
        $simpleProductType =  isset($this->templateStore['extraMapping']['simpleProductType']) ? $this->templateStore['extraMapping']['simpleProductType'] : '';

        if(!empty($productTypeField) && !empty($simpleProductType) && $simpleProductType != '') {            
            $correctData = false;

            do {            
                $data = $this->fileIterator->current();
                if (null === $data) {
                    return null;
                }

                $headers = $this->fileIterator->getHeaders();
        
                $countHeaders = count($headers);
                $countData = count($data);
                
                $this->checkColumnNumber($countHeaders, $countData, $data, $filePath);
        
                if ($countHeaders > $countData) {
                    $missingValuesCount = $countHeaders - $countData;
                    $missingValues = array_fill(0, $missingValuesCount, '');
                    $data = array_merge($data, $missingValues);
                }
        
                $data = array_combine($this->fileIterator->getHeaders(), $data);
                if(isset($data[$productTypeField]) && $data[$productTypeField] == $simpleProductType) {
                    $this->fileIterator->next();
                    $correctData = true;
                } else {
                    $correctData = false;
                }                
            } while ($correctData == true);
        } else {
            $this->stepExecution->addWarning('Template have missing values of productType field or simpleProductType', [], new \DataInvalidItem([]));
            return;
        }

        $transformedData = $this->transformData($data);
       
        $identifier = $this->connectorService->getIdentifierAttr();
        
        if(isset($transformedData[$identifier])) {
            $productData['identifier'] = $transformedData[$identifier];
        }
        
        $currency = $jobParameters->all()['filters']['structure']['currency'];
        $scope = $jobParameters->all()['filters']['structure']['scope'];
        $locale = isset($jobParameters->all()['filters']['structure']['locales'][0]) ? $jobParameters->all()['filters']['structure']['locales'][0] : ''; 
        $values = $this->connectorService->convertTransformedData($transformedData, $scope, $locale, $currency, $this->templateStore['extraMapping']['multiValueSeperator']);
        //dump($transformedData); dump($currency); dump($scope); dump($locale); dump($values); die;
        if(isset($this->templateStore['extraMapping']['enabledFieldName']) && isset($data[$this->templateStore['extraMapping']['enabledFieldName']])) {
            $productData['enabled'] = (bool)$data[$this->templateStore['extraMapping']['enabledFieldName']];
        } else {
            $productData['enabled'] = false;
        }
        
        if(isset($this->templateStore['extraMapping']['familyFieldName']) && isset($data[$this->templateStore['extraMapping']['familyFieldName']])) {
            $productData['family'] = $data[$this->templateStore['extraMapping']['familyFieldName']];
        } 
        // else {
        //     $this->stepExecution->addWarning('Family field name must not be blanked.', [], new \DataInvalidItem([]));
        //     return;
        // }
        
        // if(!isset($this->templateStore['extraMapping']['categoryFieldName']) && !isset($data[$this->templateStore['extraMapping']['categoryFieldName']])) {
        //     $this->stepExecution->addWarning('Category field must not be blanked.', [], new \DataInvalidItem([]));
        //     return;
        // }

        // if(!isset($this->templateStore['extraMapping']['exportCategoryLabel']) && !isset($data[$this->templateStore['extraMapping']['exportCategoryLabel']])) {
        //     $this->stepExecution->addWarning('Export category field must not be blanked.', [], new \DataInvalidItem([]));
        //     return;
        // }
        
        if(isset($this->templateStore['extraMapping']['categoryFieldName'])
            && !empty($this->templateStore['extraMapping']['categoryFieldName'])
            && $this->templateStore['extraMapping']['exportCategoryLabel'] == 'true'
        ) {
            $saperator = $this->templateStore['extraMapping']['multiValueSeperator'];
            $mvs = !empty($saperator) ? $saperator : '/';
            $categories = explode($mvs,$data[$this->templateStore['extraMapping']['categoryFieldName']]);
            if(!empty($categories)) {
                $category = [];
                foreach ($categories as $value) {
                    if($value) {

                        $category[] = $value;
                    }
                }
                $productData['categories'] = $category;
            }

        }
        $productData['groups'] = [];
        
        if(isset($this->templateStore['extraMapping']['parentCode']) && !empty($this->templateStore['extraMapping']['parentCode']) && isset($data[$this->templateStore['extraMapping']['parentCode']]) && !empty($data[$this->templateStore['extraMapping']['parentCode']])) {
            $productData['parent'] = $data[$this->templateStore['extraMapping']['parentCode']];
        } else {
            $productData['parent'] = null;
        }
        
        $productData['values'] = $values;
        if (!is_array($productData) || !isset($productData['values'])) {
            return $productData;
        }
        
        return $productData;
    }

    public function transformData($data)
    {   
        $response = [];
        $keys = array_keys($data);

        if(isset($this->templateStore['extraMapping']['parentCode']) && !empty($this->templateStore['extraMapping']['parentCode']) && isset($data[$this->templateStore['extraMapping']['parentCode']]) && !empty($data[$this->templateStore['extraMapping']['parentCode']]) && $data[$this->templateStore['extraMapping']['parentCode']] != 'null') {
            
            foreach ($keys as $key) {
                
                $result = [];
                if(isset($this->templateStore['rawValues'][$key])) {
                    if($this->templateStore['rawValues'][$key]['variantfieldtype'] == 'multiple') {

                        $result = $this->multipleVariantFieldResolve($data, $this->templateStore, $key);
                    } else if($this->templateStore['rawValues'][$key]['variantfieldtype'] == 'concatenate') {
                        
                        $result = $this->multipleVariantFieldResolve($data, $this->templateStore, $key, 'concate');
                    } else {
                        $result = $this->simpleVariantFieldResolve($data, $this->templateStore, $key);                        
                    }
                    if($result) {
                        foreach ($result as $attrKey => $attrValue) {                            
                            if($attrValue && $attrKey) {
                                $response[$attrKey] = $attrValue;
                            }
                        }
                    }                       
                }
            }
        } else {

            foreach ($keys as $key) {
                $result = [];
                if(isset($this->templateStore['rawValues'][$key])) {

                    if($this->templateStore['rawValues'][$key]['type'] == 'multiple') {

                        $result = $this->multipleFieldResolve($data, $this->templateStore, $key);
                    } else if($this->templateStore['rawValues'][$key]['type'] == 'concatenate') {
                        
                        $result = $this->multipleFieldResolve($data, $this->templateStore, $key, 'concate');
                    } else {
                        $result = $this->simpleFieldResolve($data, $this->templateStore, $key);                        
                    }
                    
                    if($result) {
                        
                        foreach ($result as $attrKey => $attrValue) {                            
                            if($attrValue && $attrKey) {
                                $response[$attrKey] = $attrValue;
                            }
                        }
                    }                       
                }
            }
        }

        return $response;
    }


    public function simpleVariantFieldResolve($data, $mapping, $key)
    {        
        $attrs = $mapping['rawValues'][$key]['variantattributes'];
        $response = [];
        if(isset($mapping['rawValues'][$key]['variantfieldformat'][0]) && isset($mapping['rawValues'][$key]['variantfieldformat'][1]) && isset($mapping['rawValues'][$key]['variantfieldformat'][2]) && $mapping['rawValues'][$key]['variantfieldformat'][0] == 'attributename' && $mapping['rawValues'][$key]['variantfieldformat'][1] == 'seperator' && $mapping['rawValues'][$key]['variantfieldformat'][2] == 'attributevalue') {
            $values = explode($mapping['extraMapping']['variantFormatSeperator'],$data[$key]);
            if(count($values)  > 1) {
                unset($values[0]);
            } else {
                $response[$attrs] = $values[0];
            }
            if(isset($values[1])) {
                $response[$attrs] = $values[1];
            }
	    } else if($mapping['rawValues'][$key]['attributefieldformat'][0] == 'attributename') {
            $response[$attrs] = $data[$key];
        } else if($mapping['rawValues'][$key]['attributefieldformat'][0] == 'attributevalue') {
            $response[$attrs] = $data[$key];
        }
        //  else {
        //     $this->stepExecution->addWarning('Single CSV field must have format of attributename + saperator + attributevalue Or only attributevalue', [], new \DataInvalidItem([]));
        // }

        return $response;
    }

    public function multipleVariantFieldResolve($data, $mapping, $key, $type = 'mutiple' )
    {
        $saperator = $mapping['extraMapping']['multiValueSeperator'];
        if($type == 'concate') {
            $saperator = '_';
        }

        if(isset($mapping['rawValues'][$key]['variantfieldformat'][0]) && isset($mapping['rawValues'][$key]['variantfieldformat'][1]) && isset($mapping['rawValues'][$key]['variantfieldformat'][2]) && $mapping['rawValues'][$key]['variantfieldformat'][0] == 'attributename' && $mapping['rawValues'][$key]['variantfieldformat'][1] == 'seperator' && $mapping['rawValues'][$key]['variantfieldformat'][2] == 'attributevalue' && $mapping['extraMapping']['variantFormatSeperator'] != $mapping['extraMapping']['multiValueSeperator']) {
            $response = [];
            $attrs = $mapping['rawValues'][$key]['variantattributes'];

            if(isset($attrs)) {
                if(is_array($attrs)) {
                    if($type != 'concate'){
                        $values = explode($mapping['extraMapping']['productFormatSeperator'],$data[$key]);                    

                        foreach($attrs as $key => $attr){
                            foreach ($values as $keys => $value) {
                                $attData = explode('=',$value); 
                                if(strpos(strtolower($value), $attr) !== false){
                                    $response[$attr] = $attData[1];
                                }
                            }
                        }
                    } else{
                        $values = explode($saperator,$data[$key]);                    

                        foreach($attrs as $key => $attr){
                            foreach ($values as $keys => $value) {
                                $attData = explode($mapping['extraMapping']['productFormatSeperator'],$value); 
                                if(strpos(strtolower($value), $attr) !== false){
                                    $response[$attr] = $attData[1];
                                }
                            }
                        }
                    }
                } else {
                    $response[$attrs] = $data[$key];
                }
            } 

            if($response) {
                return $response;
            }

        } 
        // else {

        //     $this->stepExecution->addWarning('Multiple CSV field must have format of attributename + saperator + attributevalue Or the Product Format saperator can not be same as multiple value saperator', [], new \DataInvalidItem([]));
        // }
        
    }


    public function simpleFieldResolve($data, $mapping, $key)
    {
        $attrs = $mapping['rawValues'][$key]['attributes'];
        $response = [];
        if(isset($mapping['rawValues'][$key]['attributefieldformat'][0]) && isset($mapping['rawValues'][$key]['attributefieldformat'][1]) && isset($mapping['rawValues'][$key]['attributefieldformat'][2]) && $mapping['rawValues'][$key]['attributefieldformat'][0] == 'attributename' && $mapping['rawValues'][$key]['attributefieldformat'][1] == 'seperator' && $mapping['rawValues'][$key]['attributefieldformat'][2] == 'attributevalue') {
            $values = explode($mapping['extraMapping']['productFormatSeperator'],$data[$key]);
            if(count($values)  > 1) {
                unset($values[0]);
            } else {
                $response[$attrs] = $values[0];
            }
            if(isset($values[1])) {
                $response[$attrs] = $values[1];
            }

        } else if($mapping['rawValues'][$key]['attributefieldformat'][0] == 'attributename') {
            $response[$attrs] = $data[$key];
        } else if($mapping['rawValues'][$key]['attributefieldformat'][0] == 'attributevalue') {
            $response[$attrs] = $data[$key];
        }
        //  else {
        //     $this->stepExecution->addWarning('Single CSV field must have format of attributename + saperator + attributevalue Or only attributevalue', [], new \DataInvalidItem([]));
        // }

        return $response;
    }

    public function multipleFieldResolve($data, $mapping, $key, $type = 'mutiple' )
    {
        $saperator = $mapping['extraMapping']['multiValueSeperator'];
        if($type == 'concate') {
            $saperator = '_';
        }

        if(isset($mapping['rawValues'][$key]['attributefieldformat'][0]) && isset($mapping['rawValues'][$key]['attributefieldformat'][1]) && isset($mapping['rawValues'][$key]['attributefieldformat'][2]) && $mapping['rawValues'][$key]['attributefieldformat'][0] == 'attributename' && $mapping['rawValues'][$key]['attributefieldformat'][1] == 'seperator' && $mapping['rawValues'][$key]['attributefieldformat'][2] == 'attributevalue' && $mapping['extraMapping']['productFormatSeperator'] != $mapping['extraMapping']['multiValueSeperator']) {
            
            $response = [];
            $attrs = $mapping['rawValues'][$key]['attributes'];
            if(isset($attrs)) {
                if(is_array($attrs)) {
                    if($type != 'concate'){
                        $values = explode($mapping['extraMapping']['productFormatSeperator'],$data[$key]);                    

                        foreach($attrs as $key => $attr){
                            foreach ($values as $keys => $value) {
                                $attData = explode('=',$value); 
                                if(strpos(strtolower($value), $attr) !== false){
                                    $response[$attr] = $attData[1];
                                }
                            }
                        }
                    } else{
                        $values = explode($saperator,$data[$key]);                    

                        foreach($attrs as $key => $attr){
                            foreach ($values as $keys => $value) {
                                $attData = explode($mapping['extraMapping']['productFormatSeperator'],$value); 
                                if(strpos(strtolower($value), $attr) !== false){
                                    $response[$attr] = $attData[1];
                                }
                            }
                        }
                    }
                } else {
                    $response[$attrs] = $data[$key];
                }
            } 

            if($response) {
                return $response;
            }

        } 
        // else {

        //     $this->stepExecution->addWarning('Multiple CSV field must have format of attributename + saperator + attributevalue Or the Product Format saperator can not be same as multiple value saperator', [], new \DataInvalidItem([]));
        // }
        
    }

    /**
     * @return array
     */
    protected function getArrayConverterOptions()
    {
        $jobParameters = $this->stepExecution->getJobParameters();

        return [
            // for the array converters
            'mapping'           => [
                $jobParameters->get('familyColumn')     => 'family',
                $jobParameters->get('categoriesColumn') => 'categories',
                $jobParameters->get('groupsColumn')     => 'groups'
            ],
            'with_associations' => false,

            // for the delocalization
            'decimal_separator' => $jobParameters->get('decimalSeparator'),
            'date_format'       => $jobParameters->get('dateFormat')
        ];
    }
}
