<?php

namespace Webkul\WebkulCsvImportBundle\DataFormatter;

class BaseFormater
{
    /**
     * Format Product Data
     *
     * @param array $item
     * @param string|null $parent
     *
     * @return array
     */
    public function formatData(array $item, ?string $parent): array
    {
        $formatted = [];
        $formatVariantAttributes = [];
        $formatCommonVariantAttributes = [];
        $formattedAttribute = $this->formatAttributes($item['values']);
        if (array_key_exists('allVariantAttributes', $item)) {
            $formatVariantAttributes = $this->formatVariantAttributes($item['values'], $item['allVariantAttributes']);
            $formatCommonVariantAttributes = $this->formatVariantAttributes($item['values'], $item['commonAttributes']);
        }
        foreach ($this->headers as $headKey => $headValue) {
            if (in_array($headValue, $this->extraMapping)) {
                $formatted[$headValue] = $this->getExtraMappingData((string) $headKey, $item);
            } else {
                $mapped = $this->storeTemplateData[$headValue];
                $value = [];
                $productBooleanValueFormat = isset($mapped['productBooleanValueFormat']) ? $mapped['productBooleanValueFormat'] : 'Yes/No';
                $variantBooleanValueFormat = isset($mapped['variantBooleanValueFormat']) ? $mapped['variantBooleanValueFormat'] : 'Yes/No';
                $multipleNormalField       = isset($mapped['attributes']) ? $mapped['attributes'] : [];
                $multipleVariantField      = isset($mapped['variantattributes']) ? $mapped['variantattributes'] : [];
                $variantFieldFormat        = isset($mapped['variantfieldformat']) ? $mapped['variantfieldformat'] : [];
                $productFieldFormat        = isset($mapped['attributefieldformat']) ? $mapped['attributefieldformat'] : [];
                $imageAttributes           = $this->connectorService->getImageAttributeCodes();
                if (!empty($multipleNormalField) || !empty($multipleVariantField)) {
                    if (isset($item['code']) || !$item['parent']) {
                        if ($mapped['concat']) {
                            if (!empty($multipleNormalField)) {
                                foreach ($multipleNormalField as $fieldsValue) {
                                    if (array_key_exists($fieldsValue, $formattedAttribute)) {
                                        if ($formattedAttribute[$fieldsValue]) {
                                            $attributeValue = in_array($fieldsValue, $imageAttributes) ? $this->connectorService->generateImageUrl($formattedAttribute[$fieldsValue]) : $this->formatAttributeValue($productFieldFormat, $this->productFormatSeperator, $fieldsValue, $formattedAttribute[$fieldsValue]);
                                            if (in_array($mapped['attributes'], $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                                $attributeValue = $this->formatBooleanValue($productBooleanValueFormat, $attributeValue);
                                            }
                                            $value[] = $attributeValue;
                                        }
                                    }
                                }
                            }
                            $formatted[$headValue][] = implode("_", $value);
                        } elseif ($mapped['type'] == 'multiple') {
                            if (!empty($multipleNormalField)) {
                                foreach ($multipleNormalField as $fieldsValue) {
                                    if (array_key_exists($fieldsValue, $formattedAttribute)) {
                                        if ($formattedAttribute[$fieldsValue]) {
                                            $attributeValue = in_array($fieldsValue, $imageAttributes) ? $this->connectorService->generateImageUrl($formattedAttribute[$fieldsValue]) : $this->formatAttributeValue($productFieldFormat, $this->productFormatSeperator, $fieldsValue, $formattedAttribute[$fieldsValue]);
                                            if (in_array($mapped['attributes'], $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                                $attributeValue = $this->formatBooleanValue($productBooleanValueFormat, $attributeValue);
                                            }

                                            $formatted[$headValue][] = $attributeValue;
                                        }
                                    }
                                }
                            }
                        } else {
                            if ($mapped['attributes'] && array_key_exists($mapped['attributes'], $formattedAttribute)) {
                                $attributeValue = in_array($mapped['attributes'], $imageAttributes) ? $this->connectorService->generateImageUrl($formattedAttribute[$mapped['attributes']]) : $this->formatAttributeValue($productFieldFormat, $this->productFormatSeperator, $mapped['attributes'], $formattedAttribute[$mapped['attributes']]);
                                if (in_array($mapped['attributes'], $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                    $attributeValue = $this->formatBooleanValue($productBooleanValueFormat, $attributeValue);
                                }

                                $formatted[$headValue][] = $attributeValue;
                            }
                        }
                    } else {
                        if ($mapped['variantconcat']) {
                            if (!empty($multipleVariantField)) {
                                foreach ($multipleVariantField as $fieldsValue) {
                                    if (in_array($headValue, $this->variantAxesField)) {
                                        if (array_key_exists($fieldsValue, $formatVariantAttributes)) {
                                            $attributeValue = in_array($fieldsValue, $imageAttributes) ? $this->connectorService->generateImageUrl($formatVariantAttributes[$fieldsValue]) : $this->formatAttributeValue($variantFieldFormat, $this->variantFormatSeperator, $fieldsValue, $formatVariantAttributes[$fieldsValue]);
                                            if (in_array($fieldsValue, $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                                $attributeValue = $this->formatBooleanValue($variantBooleanValueFormat, $attributeValue);
                                            }
                                            $value[] = $attributeValue;
                                        }
                                    } else {
                                        if (array_key_exists($fieldsValue, $formatCommonVariantAttributes)) {
                                            $attributeValue = in_array($fieldsValue, $imageAttributes) ? $this->connectorService->generateImageUrl($formatCommonVariantAttributes[$fieldsValue]) : $this->formatAttributeValue($variantFieldFormat, $this->variantFormatSeperator, $fieldsValue, $formatCommonVariantAttributes[$fieldsValue]);
                                            if (in_array($fieldsValue, $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                                $attributeValue = $this->formatBooleanValue($variantBooleanValueFormat, $attributeValue);
                                            }
                                            $value[] = $attributeValue;
                                        }
                                    }
                                }
                            }
    
                            $formatted[$headValue][] = implode("_", $value);
                        } elseif ($mapped['variantfieldtype'] == 'multiple') {
                            if (!empty($multipleVariantField)) {
                                foreach ($multipleVariantField as $fieldsValue) {
                                    if (in_array($headValue, $this->variantAxesField)) {
                                        if (array_key_exists($fieldsValue, $formatVariantAttributes)) {
                                            $attributeValue = in_array($fieldsValue, $imageAttributes) ? $this->connectorService->generateImageUrl($formatVariantAttributes[$fieldsValue]) : $this->formatAttributeValue($variantFieldFormat, $this->variantFormatSeperator, $fieldsValue, $formatVariantAttributes[$fieldsValue]);
                                            if (in_array($fieldsValue, $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                                $attributeValue = $this->formatBooleanValue($variantBooleanValueFormat, $attributeValue);
                                            }
                                            $formatted[$headValue][] = $attributeValue;
                                        }
                                    } else {
                                        if (array_key_exists($fieldsValue, $formatCommonVariantAttributes)) {
                                            $attributeValue = in_array($fieldsValue, $imageAttributes) ? $this->connectorService->generateImageUrl($formatCommonVariantAttributes[$fieldsValue]) : $this->formatAttributeValue($variantFieldFormat, $this->variantFormatSeperator, $fieldsValue, $formatCommonVariantAttributes[$fieldsValue]);
                                            if (in_array($fieldsValue, $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                                $attributeValue = $this->formatBooleanValue($variantBooleanValueFormat, $attributeValue);
                                            }
                                            $formatted[$headValue][] = $attributeValue;
                                        }
                                    }
                                }
                            }
                        } else {
                            if (!empty($mapped['variantattributes'])
                                && $mapped['variantattributes'] !== 'Select'
                                ) {
                                if (in_array($headValue, $this->variantAxesField)) {
                                    if (array_key_exists($mapped['variantattributes'], $formatVariantAttributes)) {
                                        $attributeValue = in_array($mapped['variantattributes'], $imageAttributes) ? $this->connectorService->generateImageUrl($formatVariantAttributes[$mapped['variantattributes']]) : $this->formatAttributeValue($variantFieldFormat, $this->variantFormatSeperator, $mapped['variantattributes'], $formatVariantAttributes[$mapped['variantattributes']]);
                                        if (in_array($mapped['variantattributes'], $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                            $attributeValue = $this->formatBooleanValue($variantBooleanValueFormat, $attributeValue);
                                        }
                                        $formatted[$headValue][] = $attributeValue;
                                    }
                                } else {
                                    if (array_key_exists($mapped['variantattributes'], $formatCommonVariantAttributes)) {
                                        $attributeValue = in_array($mapped['variantattributes'], $imageAttributes) ? $this->connectorService->generateImageUrl($formatCommonVariantAttributes[$mapped['variantattributes']]) : $this->formatAttributeValue($variantFieldFormat, $this->variantFormatSeperator, $mapped['variantattributes'], $formatCommonVariantAttributes[$mapped['variantattributes']]);
                                        if (in_array($mapped['variantattributes'], $this->attributeCodeByTypes['booleanAttributeCode'])) {
                                            $attributeValue = $this->formatBooleanValue($variantBooleanValueFormat, $attributeValue);
                                        }
                                        $formatted[$headValue][] = $attributeValue;
                                    }
                                }
                            }
                        }
                    }
                } else {
                    $formatted[$headValue][] = $mapped['defaultValue'];
                }

                if ($parent && isset($formatted[$parent])) {
                    foreach ($formatted[$parent] as $formattedParentKey => $formattedParentValue) {
                        $formatted[$parent][$formattedParentKey] = strtolower(str_replace(' ', '_', $formattedParentValue));
                    }
                }
            }
        }

        if (($item['parent'] && !isset($item['code'])) && $parent) {
            $parentAttributeValues = [];
            if (isset($this->storeTemplateData[$parent]['attributes']) && is_array($this->storeTemplateData[$parent]['attributes'])) {
                foreach ($this->storeTemplateData[$parent]['attributes'] as $parentAttribute) {
                    if (isset($formatCommonVariantAttributes[$parentAttribute])) {
                        $parentAttributeValues[] = $parentAttribute === 'sku' ? $item['parent'] : $formatCommonVariantAttributes[$parentAttribute];
                    }
                }
            } else {
                $parentAttributeValues = $this->storeTemplateData[$parent]['attributes'] === 'sku' ? $item['parent'] : $formatCommonVariantAttributes[$this->storeTemplateData[$parent]['attributes']];
            }

            $formatted[$parent] = !empty($parentAttributeValues) && is_array($parentAttributeValues) ? strtolower(str_replace(' ', '_', trim(implode(' ', $parentAttributeValues)))) : strtolower(str_replace(' ', '_', $parentAttributeValues));
        }

        return $this->createArray($formatted, $parent);
    }
    
    /**
     * Create Array of Formated Data
     *
     * @param array $formattedData
     * @param string|null $parent
     *
     * @return array
     */
    protected function createArray(array $formattedData, ?string $parent): array
    {
        $formatHeader = [];
        $formatValues  = [];
        $defaultArray = [];
        $all =  [];
        foreach ($formattedData as $formatkey => $formatvalue) {
            if (gettype($formatvalue) == 'array') {
                $formatHeader[$formatkey] = count($formatvalue) ;
            } else {
                $formatHeader[$formatkey] = 1;
            }
        }
        foreach ($formattedData as $formatkey => $formatvalue) {
            if (gettype($formatvalue) == 'array') {
                if (isset($this->storeTemplateData[$formatkey]) && in_array('pim_catalog_image', $this->storeTemplateData[$formatkey]['attributeTypes'])
                        && $this->storeTmpName === 'wk_akeneo_shopify_csv_export') {
                    $all[] = $formatvalue;
                } else {
                    $all[] = implode($this->multiValueSeperator, $formatvalue);
                }
            } else {
                $all[] = $formatvalue;
            }
        }

        $formatValues[] = $all;
        foreach ($formatValues as $formatValue) {
            $defaultArray[] = array_combine(array_keys($formatHeader), $formatValue);
        }

        return $defaultArray;
    }

    /**
     * Format item values
     *
     * @param array $attributes
     *
     * @return array
     */
    protected function formatAttributes(array $attributes): array
    {
        $formatedValues = [];
        foreach ($attributes as $name => $value) {
            $formatedValues[$name] = $this->formatValue($value);
            
            if (in_array($name, $this->attributeCodeByTypes['selectAttributeCodes'])) {
                $optionLabel = $this->getOptionNameByCode($name, $formatedValues[$name]);
                if ($optionLabel) {
                    $formatedValues[$name] = $optionLabel;
                }
            } elseif (in_array($name, $this->attributeCodeByTypes['multiSelectAttributeCodes']) && !empty($formatedValues[$name])) {
                $optionLabels = [];
                foreach ($formatedValues[$name] as $optionCode) {
                    $optionLabels[] = $this->getOptionNameByCode($name, $optionCode);
                }

                if (!empty($optionLabels)) {
                    $formatedValues[$name] = implode($this->multiValueSeperator, $optionLabels);
                }
            }
        }

        return $formatedValues;
    }

    /**
     * Format variant item values
     *
     * @param array $values
     * @param array $attributes
     *
     * @return array
     */
    protected function formatVariantAttributes($values, $attributes)
    {
        $formatedValues = [];
        foreach ($attributes as $name => $attribute) {
            if (isset($values[$attribute])) {
                $formatedValues[$attribute] = $this->formatValue($values[$attribute]);
                if (in_array($attribute, $this->attributeCodeByTypes['selectAttributeCodes'])) {
                    $optionLabel = $this->getOptionNameByCode($attribute, $formatedValues[$attribute]);
                    if ($optionLabel) {
                        $formatedValues[$attribute] = $optionLabel;
                    }
                } elseif (in_array($attribute, $this->attributeCodeByTypes['multiSelectAttributeCodes']) && !empty($formatedValues[$attribute])) {
                    $optionLabels = [];
                    foreach ($formatedValues[$attribute] as $optionCode) {
                        $optionLabels [] = $this->getOptionNameByCode($attribute, $optionCode);
                    }
                    
                    if (!empty($optionLabels)) {
                        $formatedValues[$attribute] = implode($this->multiValueSeperator, $optionLabels);
                    }
                }
            }
        }

        return $formatedValues;
    }

    /**
     * Get attribute type by code
     *
     * @return array
     */
    protected function getAttributeCodeByType(): array
    {
        return [
            'booleanAttributeCode' => $this->connectorService->getSelectAttributeCodes('pim_catalog_boolean'),
            "selectAttributeCodes" => $this->connectorService->getSelectAttributeCodes('pim_catalog_simpleselect'),
            "multiSelectAttributeCodes" => $this->connectorService->getSelectAttributeCodes('pim_catalog_multiselect'),
            "priceAttributeCode" => $this->connectorService->getSelectAttributeCodes('pim_catalog_price_collection'),
            "dateAttributeCode" => $this->connectorService->getSelectAttributeCodes('pim_catalog_date'),
        ];
    }
    
    /** Get option name by code
     *
     * @param string $attributeCode
     * @param string $code
     *
     * @return string|null
     */
    protected function getOptionNameByCode(string $attributeCode, string $code): ?string
    {
        if ($this->exportSelectOptionLabel != 'false') {
            $option = $this->connectorService->getOptionByCode($attributeCode.'.'.$code);
            if ($option) {
                $option->setLocale($this->locale);
                return $option->getTranslation()->getLabel();
            }

            return null;
        }

        return $code;
    }

    /**
     * Format value according to job locale
     *
     * @param $value
     *
     * @return string
     */
    protected function formatValue($value)
    {        
        if (is_array($value)) {            
            foreach ($value as $key => $aValue) {                
                if (is_array($aValue)) {
                    if (array_key_exists('locale', $aValue)) {                        
                        if (!$aValue['locale'] || $aValue['locale'] == $this->locale) {
                            $value = $aValue['data'];
                            break;
                        }
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        if ($value
            && is_array($value)
        ) {
            if (array_key_exists('unit', $value)) {
                $value = !empty($value['amount']) ? ($this->exportMetricUnit != 'false' ? $value['amount'] . ' '.$value['unit'] : $value['amount'])  : '';
            } else {
                $priceValue = $value;
                foreach ($value as $mainValue) {
                    if (is_array($mainValue)) {
                        if (array_key_exists('currency', $mainValue)
                            && $this->currency == $mainValue['currency']
                        ) {
                            $priceValue = !empty($mainValue['amount']) ? $mainValue['amount'] : '';
                        }                        

                    }                    
                }
                $value = $priceValue;
            }
        }
   
        return !empty($value) ? $value : '';
    }

    /**
     * Get extra mapping
     *
     * @param string $headKey
     * @param array  $item
     *
     * @return array
     */
    protected function getExtraMappingData(string $headKey, array $item): array
    {
        $formatteddata  = [];
        switch ($headKey) {
            case 'categoryFieldName':
                $categories = [];
                foreach ($item['categories'] as $category) {
                    $categoriesData = array_reverse($this->connectorService->getCategoryData($category, $this->locale, $this->exportRootCategory, $this->exportCategoryLabel));
                    if (!empty($categoriesData)) {
                        $categories[] = implode($this->csvCategoryDelimeter, $categoriesData);
                    }
                }
                $formatteddata[] = implode($this->categoriesSeperator, $categories);
            break;
            case 'familyFieldName':
                $family = '';
                if (isset($item['family'])) {
                    $family = $item['family'];
                } elseif (isset($item['family_variant'])) {
                    $familyVariant = $this->connectorService->getFamilyByFamilyVariant($item['family_variant']);
                    $family = $familyVariant ? $familyVariant->getFamily()->getCode() : '';
                }
                $formatteddata[] = $family;
            break;
            case 'enabledFieldName':
                $enabled = 'false';
                if (isset($item['enabled'])) {
                    $enabled = $item['enabled'] ? 'true' : 'fasle';
                }
                $formatteddata[] = $enabled;
            break;
            default:
        }
       
        return $formatteddata;
    }
    
    /**
     * Format attribute value
     *
     * @param array $attributFieldFormat
     * @param string $seperator
     * @param string $field
     * @param $value
     *
     * @return string
     */
    protected function formatAttributeValue(array $attributFieldFormat, string $seperator, string $field, $value)
    {
        $formattedAttributeValue = '';
        foreach ($attributFieldFormat as $formatField) {
            if ($formatField === 'attributename') {
                $formattedAttributeValue = $field;
                if ($this->exportAttributeLabel != 'false') {
                    $attribute = $this->connectorService->getAttributeByCode($field);
                    if ($attribute) {
                        $attribute->setLocale($this->locale);
                        $formattedAttributeValue =  $attribute->getTranslation()->getLabel();
                    }
                }
            } elseif ($formatField === 'seperator') {
                $formattedAttributeValue .= $seperator;
            } elseif ($formatField === 'attributevalue') {
                $formattedAttributeValue .= $value;
            }
        }
       
        return $formattedAttributeValue;
    }

    /**
     * Format boolean value by given format
     *
     * @param string format
     * @param bool|null $value
     */
    protected function formatBooleanValue(string $format, ?bool $value)
    {
        switch ($format) {
            case 'Yes/No':
                $value = $value ? 'Yes' : 'No';
                break;
            case 'Y/N':
                $value = $value ? 'Y' : 'N';
                break;
            case 'yes/no':
                $value = $value ? 'yes' : 'no';
                break;

            case 'True/False':
                $value = $value ? 'True' : 'False';
                break;

            case '1/0':
                $value = $value ? '1' : '0';
                break;

            case '1/2':
                $value = $value ? '1' : '2';
                break;
            default:
        }

        return $value;
    }
}
