<?php

namespace Webkul\WebkulCsvImportBundle\Services;

use Akeneo\Category\Infrastructure\Doctrine\ORM\Repository\CategoryRepository;
use Akeneo\Channel\Infrastructure\Doctrine\Repository\ChannelRepository;
use Akeneo\Pim\Enrichment\Bundle\Doctrine\ORM\Repository\ProductModelRepository;
use Akeneo\Pim\Enrichment\Bundle\Doctrine\ORM\Repository\ProductRepository;
use Akeneo\Pim\Enrichment\Component\FileStorage;
use Akeneo\Pim\Structure\Bundle\Doctrine\ORM\Repository\AttributeOptionRepository;
use Akeneo\Pim\Structure\Bundle\Doctrine\ORM\Repository\AttributeRepository;
use Akeneo\Pim\Structure\Bundle\Doctrine\ORM\Repository\FamilyVariantRepository;
use Akeneo\Tool\Component\Batch\Item\DataInvalidItem;
use Akeneo\Tool\Component\FileStorage\File\FileStorer;
use DateTime;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManager;
use Webkul\WebkulCsvImportBundle\Component\MediaFileGenerator;
use ZipArchive;

class WebkulCsvConnector
{
    const SECTION = 'webkul_csv_import_connector';
    private $stepExecution;
    private $settings = [];
    private $imageAttributeCodes = [];
    private $categoryLabels = [];
    protected $templateStore = null;
    protected $yesNoType = ['Yes', 'yes', 'Y', 'True', '1', 'TRUE', 'YES', 'true', 'y', '2'];

    public function __construct(
        private EntityManager $em,
        private AttributeRepository $attribute,
        private AttributeOptionRepository $attributeOption,
        private CategoryRepository $category,
        private $router,
        private $liip,
        private FamilyVariantRepository $familyVariant,
        private ChannelRepository $channel,
        private ProductModelRepository $productModel,
        private ProductRepository $product,
        private FileStorer $storer,
        private $uploadDir,
        private MediaFileGenerator $mediaFileGenerator,
        private Connection $connection,
        public AttributeOptionRepository $attributeOptionRepo
    ) {
        $this->uploadDir = !empty($uploadDir) ? $uploadDir : sys_get_temp_dir();
    }

    public function setStepExecution($stepExecution)
    {
        $this->stepExecution = $stepExecution;
    }

    public function getSelectAttributeCodes($attributeType)
    {
        return $this->attribute->getAttributeCodesByType(
            $attributeType
        );
    }

    public function getOptionByCode($code)
    {
        return $this->attributeOption->findOneByIdentifier(
            $code
        );
    }

    public function getAttributeByCode($code)
    {
        return $this->attribute->findOneByIdentifier(
            $code
        );
    }

    public function getIdentifierAttr()
    {
        $result = $this->attribute->getIdentifier()->getCode();

        return $result;
    }

    public function convertTransformedData($data, $scope, $locale, $currency, $seperator, $fileItterator, $dateFormate, $imageFolderPath)
    {
        $values = [];
        $jobParameters = $this->stepExecution->getJobParameters();
        $allJobParameters = $this->stepExecution->getJobParameters()->all();

        if (!$this->templateStore) {
            $template = $this->getTemplateStore(
                $allJobParameters["exportProfile"]
            );
            $storeTemplateData = json_decode($template->getRawValues(), true);
            $this->templateStore = isset($storeTemplateData["csvImportMapping"]) ? $storeTemplateData["csvImportMapping"] : [];
        }

        foreach ($data as $dataKey => $value) {
            $resp = $this->getAttributeByCode($dataKey);
            $locale = !is_array($locale) ? [$locale] : $locale;
            $values[$dataKey] = []; // Initialize an array for the current attribute key

            if ($resp) {
                $type = $resp?->getType();

                if ($type == 'pim_catalog_boolean') {
                    if ($resp->isLocalizable()) {
                        $value = is_array($value) ? $value : [$value];

                        foreach ($value as $booleanKey => $booleanValue) {
                            $value = is_array($booleanValue) && isset($booleanValue['data']) ? $booleanValue['data'] : $booleanValue;

                            if (!is_null($booleanValue)) {
                                foreach ($locale as $localWise) {
                                    $values[$dataKey][] = [
                                        "locale" =>  isset($booleanValue['locale']) && is_array($booleanValue) ? $booleanValue['locale'] : $localWise,
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        "data"   => in_array($value, $this->yesNoType) ? true : false
                                    ];
                                }
                            }
                        }
                        continue;
                    } else {
                        if ($value) {
                            $values[$dataKey][0] = [
                                "locale" => null,
                                'scope'  => $resp->isScopable() ? $scope : null,
                                "data"   => in_array($value, $this->yesNoType) ? true : false
                            ];
                        }
                    }
                }

                foreach ($locale as $localWise) {
                    if ($type == 'pim_catalog_metric') {
                        if (is_array($value)) {
                            $measurementData = [];

                            foreach ($value as $metricKey => $metricDatas) {
                                $metricData = !is_null($metricDatas['data']) ? explode(' ', $metricDatas['data']) : [];
                                $measurementData[$metricKey] = [
                                    "locale" => $metricDatas['locale'],
                                    "scope"  => $resp->isScopable() ? $scope : null,
                                    "data"   => [
                                        "amount" => isset($metricData[0])  ? $metricData[0] : null,
                                        "unit"   => isset($metricData[1]) ? $metricData[1] : $resp->getDefaultMetricUnit()
                                    ]
                                ];
                            }

                            $values[$dataKey] = $measurementData;
                            continue;
                        }

                        $metricData = !is_null($value) && !is_array($value) ? explode(' ', $value) : [];

                        if ($resp->isLocalizable()) {
                            $values[$dataKey][] = [
                                "locale" => $localWise,
                                "scope"  => $resp->isScopable() ? $scope : null,
                                "data"   => [
                                    "amount" => isset($metricData[0])  ? $metricData[0] : null,
                                    "unit"   => isset($metricData[1]) ? $metricData[1] : $resp->getDefaultMetricUnit()
                                ]
                            ];
                        } else {
                            $values[$dataKey][0] = [
                                "locale" => null,
                                "scope"  => $resp->isScopable() ? $scope : null,
                                "data"   => [
                                    "amount" => isset($metricData[0]) ? $metricData[0] : null,
                                    "unit"   => isset($metricData[1]) ? $metricData[1] : $resp->getDefaultMetricUnit()
                                ]
                            ];
                        }
                    } elseif ($type == 'pim_catalog_textarea' || $type == 'pim_catalog_text') {
                        if ($value) {
                            if (gettype($value) == 'string') {
                                $data = [];

                                if ($resp->isLocalizable()) {
                                    $values[$dataKey][]  = [
                                        'locale' => $localWise,
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        'data'   => $value,
                                    ];
                                } else {
                                    $values[$dataKey][0] = [
                                        'locale' => null,
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        'data'   => $value,
                                    ];
                                }
                            } else {
                                $values[$dataKey] = $value; // Assign the value directly
                            }
                        }
                    } elseif ($type == 'pim_catalog_price_collection') {
                        if (gettype($value) == 'string' || $value == null) {
                            $currency = !is_array($currency) ? [$currency] : $currency;
                            $data = [];

                            foreach ($currency as $currecnyWise) {
                                $data[] = [
                                    "amount"   => $value,
                                    "currency" => $currecnyWise
                                ];
                            }

                            if ($resp->isLocalizable()) {
                                $values[$dataKey][] = [
                                    "locale" => $localWise,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => $data
                                ];
                            } else {
                                $values[$dataKey][0] = [
                                    "locale" => null,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => $data
                                ];
                            }
                        } else {
                            $values[$dataKey] = $value; // Assign the value directly
                        }
                    } elseif ($type == 'pim_catalog_image' || $type == 'pim_catalog_file') {
                        $image = false;

                        if (is_array($value)) {
                            $imageData = $value;
                            $checkImages = false;

                            foreach ($imageData as $imageKey => $imageValue) {
                                if (!is_null($imageValue['data'])) {
                                    if ($imageFolderPath) {
                                        $isUrl = filter_var($imageValue['data'], FILTER_VALIDATE_URL);

                                        if (!$isUrl)
                                            $checkImages = $this->checkImageFolder($imageFolderPath, $imageValue['data']);
                                    }
                                }

                                if (!$checkImages) {
                                    $values[$dataKey][$imageKey] = [
                                        "locale" => $imageValue['locale'],
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        "data"   => ($this->imageStorer($imageValue['data'], $fileItterator, $imageFolderPath)) ? $this->imageStorer($imageValue['data'], $fileItterator, $imageFolderPath) : null
                                    ];
                                } else {
                                    $values[$dataKey][$imageKey] = [
                                        "locale" => $imageValue['locale'],
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        "data"   => $checkImages
                                    ];
                                }
                            }
                            continue;
                        }

                        if ($value) {
                            if ($imageFolderPath) {
                                $isUrl = filter_var($value, FILTER_VALIDATE_URL);
                                if (!$isUrl)
                                    $image = $this->checkImageFolder($imageFolderPath, $value);
                            }
                        }

                        if (!$image) {
                            if ($resp->isLocalizable()) {
                                $values[$dataKey][] = [
                                    "locale" => $localWise,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => ($this->imageStorer($value, $fileItterator, $imageFolderPath)) ? $this->imageStorer($value, $fileItterator, $imageFolderPath) : null
                                ];
                            } else {
                                $values[$dataKey][0] = [
                                    "locale" => null,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => ($this->imageStorer($value, $fileItterator, $imageFolderPath)) ? $this->imageStorer($value, $fileItterator, $imageFolderPath) : null
                                ];
                            }
                        } else {
                            if ($resp->isLocalizable()) {
                                $values[$dataKey][] = [
                                    "locale" => $localWise,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => $image
                                ];
                            } else {
                                $values[$dataKey][0] = [
                                    "locale" => null,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => $image
                                ];
                            }
                        }
                    } elseif ($type == 'pim_catalog_multiselect') {
                        $seperatorVal = ($seperator) ? $seperator : ',';

                        if (is_array($value)) {
                            $multiData = [];

                            foreach ($value as $multiKey => $multiDatas) {
                                $getAttributeOptionsCode = $this->byOptionsCodesByLabel($multiDatas['data'], $seperatorVal);

                                if ($getAttributeOptionsCode) {
                                    $multiData[$multiKey] = [
                                        "locale" => $multiDatas['locale'],
                                        "scope"  => $resp->isScopable() ? $scope : null,
                                        "data"   => $getAttributeOptionsCode
                                    ];
                                } else {
                                    $multiData[$multiKey] = [
                                        "locale" => $multiDatas['locale'],
                                        "scope"  => $resp->isScopable() ? $scope : null,
                                        "data"   => (!is_null($multiDatas['data'])) ? explode($seperatorVal, $multiDatas['data']) : null
                                    ];
                                }
                            }
                            $values[$dataKey] = $multiData;
                            continue;
                        }

                        $getAttributeOptionsCode = $this->byOptionsCodesByLabel($value, $seperatorVal);

                        if ($getAttributeOptionsCode) {
                            if ($resp->isLocalizable()) {
                                $values[$dataKey][] = [
                                    "locale" => $localWise,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => $getAttributeOptionsCode
                                ];
                            } else {
                                $values[$dataKey][0] = [
                                    "locale" =>  null,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => $getAttributeOptionsCode
                                ];
                            }
                        } else {
                            if ($resp->isLocalizable()) {
                                $values[$dataKey][] = [
                                    "locale" =>  $localWise,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => ($value) ? explode($seperatorVal, $value) : null
                                ];
                            } else {
                                $values[$dataKey][0] = [
                                    "locale" => null,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    "data"   => ($value) ? explode($seperatorVal, $value) : null
                                ];
                            }
                        }
                    } elseif ($type == 'pim_catalog_date') {
                        if (gettype($value) == 'string' || $value == null) {
                            try {
                                $date = new DateTime($value);
                                $formattedDate = !empty($value) ? $date->format('Y-m-d') : '';

                                if ($resp->isLocalizable()) {
                                    $values[$dataKey][] = [
                                        'locale' =>  $localWise,
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        'data'   => $formattedDate,
                                    ];
                                } else {
                                    $values[$dataKey][0] = [
                                        'locale' => null,
                                        'scope'  => $resp->isScopable() ? $scope : null,
                                        'data'   => $formattedDate,
                                    ];
                                }
                            } catch (\Exception $e) {
                            }
                        } else {
                            $values[$dataKey] = $value;
                        }
                    } else {
                        if ($type == 'pim_catalog_boolean')
                            continue;

                        if (gettype($value) == 'string' || $value == null) {
                            if ($resp->isLocalizable()) {
                                $values[$dataKey][] = [
                                    'locale' => $localWise,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    'data'   => $value,
                                ];
                            } else {
                                $values[$dataKey][0] = [
                                    'locale' =>  null,
                                    'scope'  => $resp->isScopable() ? $scope : null,
                                    'data'   => $value,
                                ];
                            }
                        } else {
                            $values[$dataKey] = $value;
                        }
                    }
                }
            }
        }

        return $values;
    }

    protected function imageStorer($filePath, $fileItterator, $imageFolderPath)
    {
        if ($filePath) {
            $localImagePath = $this->getImagePath($filePath, $fileItterator, $imageFolderPath);

            if ($localImagePath !== null) {
                $rawFile = new \SplFileInfo($localImagePath);
                $file = $this->storer->store($rawFile, FileStorage::CATALOG_STORAGE_ALIAS);

                return $localImagePath;
            }
        }

        return null;
    }

    public function getImagePath($filePath, $fileItterator, $imageFolderPath)
    {
        $isUrl = filter_var($filePath, FILTER_VALIDATE_URL);
        $fileName = $isUrl ? basename(parse_url($filePath, PHP_URL_PATH)) : basename($filePath);
        $fileNameWithExtension =  $fileName;
        $localPath = $this->uploadDir . "/tmpstorage/";
        $localImagePath = $localPath . $fileNameWithExtension;

        if (!$isUrl) {
            $filePath = $fileItterator . '/' . $filePath;
        }

        if (!file_exists($localPath)) {
            mkdir($localPath, 0777, true);
        }

        $imageData = $isUrl ? $this->grabImage($filePath) : file_get_contents($filePath);

        try {
            $imageData = $isUrl ? $this->grabImage($filePath) : file_get_contents($filePath);

            if ($imageData !== false) {
                file_put_contents($localImagePath, $imageData);
                $imageSize = @getimagesize($localImagePath);

                return $localImagePath;
            } else {
                throw new \Exception("Failed to retrieve image from URL or file path: $filePath");
            }
        } catch (\Exception $e) {
            throw new \Exception($e->getmessage() . ', and this image does not' . " \"$fileName\" " . ' exist in the file ' . $imageFolderPath);
        }
    }

    protected function grabImage($imageUrl)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $imageUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // Enable SSL certificate verification (recommended for production)

        try {
            $imageData = curl_exec($ch);

            if ($imageData === false) {
                $error = curl_error($ch);
                throw new \Exception("Failed to retrieve image from URL: $imageUrl");
            }
            curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
            curl_getinfo($ch, CURLINFO_HTTP_CODE);

            return $imageData;
        } catch (\Exception $e) {
            return false;
        }
    }

    public function checkImageFolder($imageFolderPath, $value)
    {
        $fileInfo = pathinfo($imageFolderPath);
        $dirName = dirname($imageFolderPath);
        $file = $dirName . '/' . $fileInfo['filename'];
        $imagePath = $file . '/' . $value;
        $path = false;
        $zip = new ZipArchive();
        $isZip = $zip->open($imageFolderPath);

        if (file_exists($imagePath)) {
            $path = $this->getImageAsZipOrFolder($imagePath, $file);
        }

        if ($isZip === true) {
            $zip->extractTo($dirName);
            $zip->close();

            if (file_exists($imagePath)) {
                $path = $this->getImageAsZipOrFolder($imagePath, $file);
            }
        }

        return $path;
    }

    public function getImageAsZipOrFolder($imagePath, $file)
    {
        $getImage = file_get_contents($imagePath);
        $localPath = $this->uploadDir . "/tmpstorage/";
        $localImagePath = $localPath . basename($imagePath);

        try {
            file_put_contents($localImagePath, $getImage);
        } catch (\Exception $e) {
        }

        return $localImagePath;
    }

    /**
     * Get Catgory Data
     *
     * @param string $code
     * @param string $locale
     * @param string $exportRootCategory
     * @param string $exportCategoryLabel
     *
     * @return array
     */
    public function getCategoryData($code, $locale, $exportRootCategory, $exportCategoryLabel)
    {
        $repository = $this->category;
        $value = $repository->findOneBy(['code' => $code]);

        if ($value->getTranslations()->getValues()) {
            if ($exportCategoryLabel != 'false') {
                foreach ($value->getTranslations()->getValues() as $catdata) {
                    if ($catdata->getLocale() == $locale) {
                        if ($value->isRoot()) {
                            if ($exportRootCategory != 'false') {
                                $this->categoryLabels[] = $catdata->getLabel();
                            }
                        } else {
                            $this->categoryLabels[] = $catdata->getLabel();
                        }
                    }
                }
            } else {
                if ($value->isRoot()) {
                    if ($exportRootCategory != 'false') {
                        $this->categoryLabels[] = $value->getCode();
                    }
                } else {
                    $this->categoryLabels[] = $value->getCode();
                }
            }

            if (!$value->isRoot()) {
                return $this->getCategoryData($value->getParent()->getCode(), $locale, $exportRootCategory, $exportCategoryLabel);
            }
        }

        $categoryLabels = $this->categoryLabels;
        $this->categoryLabels = [];

        return $categoryLabels;
    }

    public function checkParentCategory($cate)
    {
        $category = $this->category->findOneBy(['code' => $cate]);

        if ($category?->isRoot()) {
            return false;
        }

        return true;
    }

    public function getHostSettings($section = self::SECTION)
    {
        $repo = $this->em->getRepository('OroConfigBundle:ConfigValue');

        if (empty($settings)) {
            $configs = $repo->findBy([
                'section' => $section
            ]);
            $settings = $this->indexHostValuesByName($configs);
        }

        return $settings;
    }

    private function indexHostValuesByName($values)
    {
        $result = [];

        foreach ($values as $value) {
            $result[$value->getName()] = $value->getValue();
        }

        return $result;
    }

    public function getImageAttributeCodes()
    {
        if (empty($this->imageAttributeCodes)) {
            $this->imageAttributeCodes = $this->attribute->getAttributeCodesByType(
                'pim_catalog_image'
            );
        }

        return $this->imageAttributeCodes;
    }

    protected function formatApiUrl($url)
    {
        $url = str_replace(['http://'], ['https://'], $url);

        return \rtrim($url, '/');
    }

    public function getTemplateStore($id)
    {
        $templateStore = $this->em->getRepository('WebkulCsvImportBundle:TemplateConfiguration')->findOneBy([
            'id' => $id,
            "active" => 1
        ]);

        return $templateStore;
    }

    public function getFamilyByFamilyVariant($familyVariant)
    {
        return $this->familyVariant->findOneByIdentifier($familyVariant);
    }

    public function getChannelData($scope)
    {
        $channelRepo = $this->channel->findOneByIdentifier([
            $scope
        ]);

        return $channelRepo;
    }

    public function getProductModelVariants(string $code): array
    {
        $products = [];
        $productModelRepo = $this->productModel;
        $results = $productModelRepo->createQueryBuilder('m')
            ->select('p.identifier')
            ->leftJoin('m.products', 'p')
            ->where('m.code = :code')
            ->setParameter('code', $code)
            ->getQuery()->getResult();

        if (!empty($results)) {
            foreach ($results as $result) {
                $products[] = $this->getProductByIdentifier($result['identifier']);
            }
        }

        return $products;
    }

    public function transformData($templateStore, $data, $scope, $locale, $currency)
    {
        $response = [];
        $newData = [];
        $jobLocales = $locale;
        $channel = $scope;

        foreach ($data as $key => $value) {
            if (preg_match('/^(.+)-([a-zA-Z]{2}_[a-zA-Z]{2})$/', $key, $matches)) {
                $fieldName = $matches[1];
                $locale = $matches[2];

                if ((is_array($jobLocales) && in_array($locale, $jobLocales)) || $jobLocales == $locale) {
                    if (!isset($newData[$fieldName]) || !is_array($newData[$fieldName])) {
                        $newData[$fieldName] = [];
                    }

                    $newData[$fieldName][] = [
                        'locale' => $locale,
                        'scope' => null,
                        'data' => $value
                    ];
                }
            } elseif (preg_match('/^(.+)[-]([A-Z]{3})$/', $key, $matches)) { // Price collections
                if (preg_match('/^(.+?)-([a-z]{2}_[A-Z]{2})-([A-Z]{3})$/', $key, $matchesCurrency)) {
                    $fieldName = $matchesCurrency[1];
                    $locale = $matchesCurrency[2];
                    $priceCurrency = $matchesCurrency[3];
                    $resp = $this->getAttributeByCode($fieldName);
                    $localeIndex = null;

                    if (!isset($newData[$fieldName]) || !is_array($newData[$fieldName])) {
                        $newData[$fieldName] = [];
                    }

                    foreach ($newData[$fieldName] as $index => $entry) {
                        if ($entry['locale'] === $locale) {
                            $localeIndex = $index;
                            break;
                        }
                    }

                    if ($localeIndex !== null) {
                        // Append currency data to existing locale entry
                        $newData[$fieldName][$localeIndex]['data'][] = [
                            "amount" => $value,
                            "currency" => $priceCurrency
                        ];
                    } else {
                        // Add new entry for locale
                        $newData[$fieldName][] = [
                            "locale" => $locale,
                            "scope" => $resp?->isScopable() ? $channel : null,
                            "data" => [
                                [
                                    "amount" => $value,
                                    "currency" => $priceCurrency
                                ]
                            ]
                        ];
                    }
                    continue;
                }

                $fieldName = $matches[1];
                $priceCurrency = $matches[2];
                $resp = $this->getAttributeByCode($fieldName);
                $currency = !is_array($currency) ? explode(' ', $currency) : $currency;
                $existingField = null;

                if (!isset($newData[$fieldName]) || !is_array($newData[$fieldName])) {
                    $newData[$fieldName] = [];
                }

                if ((is_array($currency) && in_array($priceCurrency, $currency)) || $priceCurrency == $currency) {
                    foreach ($newData[$fieldName] as $index => $data) {
                        if ($data['locale'] === null && $data['scope'] === null) {
                            $existingField = $index;
                            break;
                        }
                    }

                    // If field exists, add the new data to the existing array
                    if ($existingField !== null) {
                        $newData[$fieldName][$existingField]['data'][] = [
                            "amount" => $value,
                            "currency" => $priceCurrency
                        ];
                    } else {
                        // If field doesn't exist, create a new one
                        $newData[$fieldName][] = [
                            "locale" => null,
                            "scope" => null,
                            "data" => [
                                [
                                    "amount" => $value,
                                    "currency" => $priceCurrency
                                ]
                            ]
                        ];
                    }
                }
            } elseif (preg_match('/^([a-zA-Z_]+)-([a-zA-Z]{2}_[a-zA-Z]{2})-([a-zA-Z_]+)$/', $key, $matches)) {
                $fieldName = $matches[1];
                $locale = $matches[2];
                $scope = $matches[3];

                if ((is_array($jobLocales) && in_array($locale, $jobLocales)) && $scope === $channel) {
                    if (!isset($newData[$fieldName]) || !is_array($newData[$fieldName])) {
                        $newData[$fieldName] = [];
                    }

                    $newData[$fieldName][] = [
                        'locale' => $locale,
                        'scope' => $scope,
                        'data' => $value
                    ];
                } elseif (!is_array($jobLocales) && $locale === $jobLocales && $scope === $channel) {
                    if (!isset($newData[$fieldName]) || !is_array($newData[$fieldName])) {
                        $newData[$fieldName] = [];
                    }

                    $newData[$fieldName][] = [
                        'locale' => $locale,
                        'scope' => $scope,
                        'data' => $value
                    ];
                }
            } else {
                $newData[$key] = $value;
            }
        }

        $data = $newData;
        $keys = array_keys($newData);

        foreach ($keys as $key) {
            $result = [];

            if (isset($templateStore["rawValues"][$key])) {
                if ($templateStore["rawValues"][$key]["type"] == "simple") {
                    $result = $this->simpleFieldResolve(
                        $data,
                        $templateStore,
                        $key
                    );
                }

                if ($result) {
                    foreach ($result as $attrKey => $attrValue) {
                        $response[$attrKey] = $attrValue;
                    }
                }
            }
        }

        foreach ($keys as $key) {
            $resp = $this->getAttributeByCode($key);

            if (isset($templateStore["rawValues"][$key])) {
                if ($templateStore["rawValues"][$key]["type"] == "concatenate" || $templateStore["rawValues"][$key]["type"] == "multiple") {
                    $result = [];
                    $type = $resp->getbackendType();

                    if ($type !== 'textarea' && $type !== 'text') {
                        $this->stepExecution->addWarning(
                            "In Product and Model field mapping, for Multiple and Concate Attribute fields only text and textarea type attributes are allowed to map. The mapped attribute is type of " . "\"$type\"",
                            [],
                            new DataInvalidItem([])
                        );
                    } else {
                        $result = $this->multipleFieldResolve(
                            $templateStore,
                            $key,
                            $data
                        );
                    }

                    if (!empty($result)) {
                        $nonLocalised = implode(' ', $result['nonlocale']);
                        $multiLocaleData = [];
                        $localeData = '';
                        foreach ($jobLocales as $locale) {
                            if (isset($result['locale'][$locale]) && $result['locale'][$locale]) {
                                $localeData =  ' ' . implode(' ', $result['locale'][$locale]);
                            }

                            $multiLocaleData[] = [
                                'locale' => $resp->isLocalizable() ? $locale : null,
                                'scope'  => $resp->isScopable() ? $scope : null,
                                'data'   => $nonLocalised . $localeData
                            ];
                        }

                        $response[$key] = $multiLocaleData;
                    }
                }
            }
        }

        return $response;
    }

    public function validateData($transformedData)
    {
        /**
         * This pattern is used to check the following date formate value
         * ['yyyy-MM-dd', 'yyyy/MM/dd','dd/MM/yyyy', 'dd.MM.yyyy']
         */
        $pattern1 = '/^(?:(?:0[1-9]|[12][0-9]|3[01])[-\/.](?:0[1-9]|1[0-2])[-\/.]\d{4})|(?:\d{4}[-\/.](?:0[1-9]|1[0-2])[-\/.](?:0[1-9]|[12][0-9]|3[01]))$/';

        /**
         * This pattern is used to check the following date formate value
         * ["MM/dd/yyyy"]
         */
        $pattern2 = '/^(?:(?:0[1-9]|1[0-2])[-\/.](?:0[1-9]|[12][0-9]|3[01])[-\/.]\d{4})|(?:\d{4}[-\/.](?:0[1-9]|1[0-2])[-\/.](?:0[1-9]|[12][0-9]|3[01]))$/';

        foreach ($transformedData as $dataKey => $value) {
            $dataType = $this->getAttributeByCode($dataKey)?->getType();

            if ($dataType == 'pim_catalog_date') {
                $dateData = $value;
                $invalid = false;

                if (is_array($dateData)) {
                    foreach ($dateData as $key => $dateValue) {
                        $validate1 = preg_match($pattern1, $dateValue['data']);
                        $validate2 = preg_match($pattern2, $dateValue['data']);

                        if (!is_null($dateValue['data']) && (!$validate1 && !$validate2)) {
                            $dateValue = $dateValue['data'];
                            $this->stepExecution->addWarning(
                                "$dataKey" . ": The attribute value " . "'$dateValue'" . " does not matches with the allowed values in these date formates: " . "[' yyyy-MM-dd ', ' yyyy/MM/dd ',' dd/MM/yyyy ', ' dd.MM.yyyy ',' MM/dd/yyyy']",
                                [],
                                new DataInvalidItem([])
                            );

                            $invalid = true;
                            unset($transformedData[$dataKey]);
                        } else {
                            try {
                                $date = new DateTime($dateValue['data']);
                                $dateData[$key]['data'] = !is_null($dateValue['data']) ? $date->format('Y-m-d') : '';
                            } catch (\Exception $e) {
                            }
                        }
                    }

                    if (!$invalid)
                        $transformedData[$dataKey] = $dateData;
                    continue;
                }

                $valid1 = preg_match($pattern1, $value);
                $valid2 = preg_match($pattern2, $value);

                if (!empty($value) && !is_array($value)  && (!$valid1 && !$valid2)) {
                    $this->stepExecution->addWarning(
                        "$dataKey" . ": The attribute value " . "'$value'" . " does not matches with the allowed values in these date formates: " . "[' yyyy-MM-dd ', ' yyyy/MM/dd ',' dd/MM/yyyy ', ' dd.MM.yyyy ',' MM/dd/yyyy']",
                        [],
                        new DataInvalidItem([])
                    );
                    unset($transformedData[$dataKey]);
                }
            }

            if ($dataType === 'pim_catalog_price_collection') {
                if (empty($value))
                    unset($transformedData[$dataKey]);
            }
        }

        return $transformedData;
    }

    public function simpleFieldResolve($data, $mapping, $key)
    {
        $response = [];

        if (!empty($mapping["rawValues"][$key]["attributes"])) {
            $attrs = $mapping["rawValues"][$key]["attributes"];

            if ($mapping["rawValues"][$key]["attributefieldformat"] == "attributename") {
                $response[$attrs] = $data[$key];
            }
        }

        return $response;
    }

    public function multipleFieldResolve(
        $mapping,
        $key,
        $result
    ) {
        $attributeValues = [];
        $dataValue = [];
        $nonLocalizedValues = [];

        if (!empty($mapping["rawValues"][$key]["attributes"])) {
            $attrs = $mapping["rawValues"][$key]["attributes"];

            if (is_array($attrs)) {
                foreach ($attrs as $attr) {

                    if (isset($result[$attr])) {
                        $attributeValues[$attr] = $result[$attr];
                    }
                }

                foreach ($attributeValues as $attributeKey => $attributeValue) {
                    if (is_array($attributeValue)) {
                        foreach ($attributeValue as $value) {
                            if (isset($value['locale']) && isset($value['data']) && !is_null($value['data'])) {
                                if (!isset($dataValue['locale'][$value['locale']])) {
                                    $dataValue['locale'][$value['locale']] = [];
                                }

                                $arrayDatas = [];

                                if (is_array($value['data'])) {
                                    $arrayData = $value['data'];

                                    foreach ($arrayData as $data) {
                                        if (isset($data['amount']) && !is_null($data['amount']))
                                            $arrayDatas[] = (implode(' ', $data));
                                    }
                                }

                                $arrayDatas = empty($arrayDatas) ? '' : implode(' ', $arrayDatas);
                                $dataValue['locale'][$value['locale']][] = is_array($value['data']) ? $arrayDatas : $value['data'];
                            }
                        }
                    } else {
                        $nonLocalizedValues[] = $attributeValue;
                    }
                }
                $dataValue['nonlocale'] = $nonLocalizedValues;

                return $dataValue;
            }
        }
    }

    public function getProductByIdentifier($identifier)
    {
        return $this->product->findOneByIdentifier($identifier);
    }

    /**
     * Return extra mapping of current template
     *
     * @param string $mappinngType
     *
     * @return array
     */
    public function getExtraMappingByMappingType($mappinngType)
    {
        $parameters         = $this->stepExecution->getJobParameters()->all();
        $templateStore      = $this->getTemplateStore($parameters['exportProfile']);
        $storeTemplateData  = json_decode($templateStore->getRawValues(), true);
        $storeTemplateData  = isset($storeTemplateData[$mappinngType]) ? $storeTemplateData[$mappinngType] : [];

        return isset($storeTemplateData['extraMapping']) ? $storeTemplateData['extraMapping'] : [];
    }

    public function byOptionsCodesByLabel($optionsLabel, $seperator)
    {
        if (empty($optionsLabel)) {
            return [];
        }

        $optionsLabel = explode($seperator, $optionsLabel);
        $attributeOptionsCodeByLabel = [];

        foreach ($optionsLabel as $key => $value) {
            $sql = <<<SQL
        SELECT
        c.code AS code
        FROM pim_catalog_attribute_option c
        INNER JOIN pim_catalog_attribute_option_value trans ON c.id = trans.option_id
        WHERE trans.value LIKE ("$value")
        SQL;

            $rows = $this->connection->executeQuery($sql)->fetchAllAssociative();
            foreach ($rows as $row) {
                $attributeOptionsCodeByLabel[] = $row["code"];
            }
        }

        return array_unique($attributeOptionsCodeByLabel);
    }
}
