<?php

namespace Webkul\WebkulCsvImportBundle\Connector\Reader\Csv;

use Akeneo\Pim\Enrichment\Component\Category\Query\CountTreesChildrenInterface;
use Akeneo\Tool\Component\Batch\Item\DataInvalidItem;
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 Doctrine\DBAL\Connection;
use Webkul\WebkulCsvImportBundle\Services\WebkulCsvConnector;

class ProductModelReader extends Reader implements FileReaderInterface
{
    protected $templateStore = null;

    public function __construct(
        FileIteratorFactory $fileIteratorFactory,
        ArrayConverterInterface $converter,
        protected MediaPathTransformer $mediaPathTransformer,
        public WebkulCsvConnector $connectorService,
        private Connection $connection,
        public CountTreesChildrenInterface $countTreesChildrenQuery,
        array $options = []
    ) {
        parent::__construct($fileIteratorFactory, $converter, $options);
    }

    /**
     * {@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"]
            );

            if (!$template) {
                $this->stepExecution->addWarning(
                    "Select template or selected template status is disabled.",
                    [],
                    new DataInvalidItem([])
                );

                return;
            }

            $storeTemplateData = json_decode($template->getRawValues(), true);
            $this->templateStore = isset($storeTemplateData["csvImportMapping"])
                ? $storeTemplateData["csvImportMapping"]
                : [];
        }

        $filePath = $jobParameters->get('storage')['file_path'];

        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();
        $productTypeField = isset($this->templateStore["extraMapping"]["productTypeFieldName"]) ? $this->templateStore["extraMapping"]["productTypeFieldName"] : "";
        $productModelType = isset($this->templateStore["extraMapping"]["modelProductType"]) ? $this->templateStore["extraMapping"]["modelProductType"] : "";
        $correctData = false;

        do {
            $data = $this->fileIterator->current();

            if (null === $data) {
                return null;
            }

            $data = array_map(function ($data) {
                return $data == "" ? null : $data;
            }, $data);

            $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] == $productModelType) {
                $this->fileIterator->next();
                $correctData = true;
            } else {
                $correctData = false;
            }
        } while ($correctData == true);

        if (array_key_exists("parent", $data)) {
            if (null == $data["parent"] || empty($data["parent"]) || isset($data["code"])) {
                $this->stepExecution->incrementSummaryInfo("item_position");
            } elseif (isset($data["parent"])) {
                $this->stepExecution->incrementSummaryInfo("item_position");
            }
        } else {
            if (isset($data["[code]"])) {
                $this->stepExecution->incrementSummaryInfo("item_position");
            } else {
                $this->stepExecution->incrementSummaryInfo("item_position");
            }
        }

        $csvData = $data;
        $currency = $jobParameters->all()["filters"]["structure"]["currency"];
        $scope = $jobParameters->all()["filters"]["structure"]["scope"];
        $locale = isset($jobParameters->all()["filters"]["structure"]["locales"]) ? $jobParameters->all()["filters"]["structure"]["locales"] : "";
        $transformedData = $this->connectorService->transformData($this->templateStore, $data, $scope, $locale, $currency);
        $dateFormat = $allJobParameters['dateFormat'];
        $imageFolderPath = $allJobParameters['imageFolder'];
        $transformedData = $this->connectorService->validateData($transformedData);

        if (empty($transformedData)) {
            $this->stepExecution->addWarning(
                "Attribute does not mapped or CSV delimiter is not appropriate",
                [],
                new DataInvalidItem([])
            );

            return;
        }

        $identifier = $this->connectorService->getIdentifierAttr();

        if (isset($data["sku"]) || isset($data["SKU"])) {
            if (isset($transformedData[$identifier])) {
                $productData["code"] = $transformedData[$identifier];
            } elseif (isset($data["sku"]) || isset($data["SKU"])) {
                $productData["code"] = isset($data["SKU"]) ? $data["SKU"] : $data["sku"];
            } else {
                $this->stepExecution->addWarning(
                    "Product Model code should not be blank",
                    [],
                    new DataInvalidItem([])
                );

                return;
            }
        } else {
            $this->stepExecution->addWarning(
                "Identfier header does not match with the CSV file and the template mapping for model products.",
                [],
                new DataInvalidItem([])
            );
        }

        $values = $this->connectorService->convertTransformedData(
            $transformedData,
            $scope,
            $locale,
            $currency,
            isset($this->templateStore["extraMapping"]["multiValueSeperator"]) && !empty($this->templateStore["extraMapping"]["multiValueSeperator"]) ? ($this->templateStore["extraMapping"]["multiValueSeperator"]) : ',',
            $this->fileIterator->getDirectoryPath(),
            $dateFormat,
            $imageFolderPath
        );

        if (!isset($this->templateStore["extraMapping"]["exportAttributeLabel"]) && !isset($this->templateStore["extraMapping"]["exportCategoryLabel"])) {
            $this->templateStore["extraMapping"]["exportAttributeLabel"] = 'false';
            $this->templateStore["extraMapping"]["exportCategoryLabel"] = 'false';
        }

        if ((isset($this->templateStore["extraMapping"]["exportAttributeLabel"]) && "false" == $this->templateStore["extraMapping"]["exportAttributeLabel"])) {
            if (isset($this->templateStore["extraMapping"]["familyVariantFieldName"]) && $this->templateStore["extraMapping"]["familyVariantFieldName"] !== '') {
                if (array_key_exists($this->templateStore["extraMapping"]["familyVariantFieldName"], $data)) {
                    $productData["family_variant"] = $data[$this->templateStore["extraMapping"]["familyVariantFieldName"]] ?? '';
                }
            }
        }

        if (
            isset($this->templateStore["extraMapping"]["categoryFieldName"]) &&
            $this->templateStore["extraMapping"]["exportCategoryLabel"] == "false"
        ) {
            if (!array_key_exists($this->templateStore["extraMapping"]["categoryFieldName"], $csvData)) {
                $this->stepExecution->addWarning(
                    "Category header in the CSV file is not defined as the category field value in the template.",
                    [],
                    new DataInvalidItem([])
                );
            } else {
                $productCategory = null;
                $saperator =
                    isset($this->templateStore["extraMapping"]["multiValueSeperator"]) && !empty($this->templateStore["extraMapping"]["multiValueSeperator"]) ? $this->templateStore["extraMapping"]["multiValueSeperator"] : null;
                $mvs = !empty($saperator) ? $saperator : ",";

                if (isset($data[$this->templateStore["extraMapping"]["categoryFieldName"]])) {
                    $productCategory = $data[$this->templateStore["extraMapping"]["categoryFieldName"]] ?? null;
                }

                if (null === $productCategory) {
                    $productData["categories"] = [];
                }

                if ($productCategory && null !== $productCategory) {
                    $categories = explode(
                        $mvs,
                        $productCategory
                    );
                }

                if (!empty($categories)) {
                    $category = [];
                    foreach ($categories as $value) {
                        if ($value) {
                            $category[] = $value;
                        }
                    }

                    $getAllCategories = $this->countTreesChildrenAction();
                    $checkRootCategory = $category;

                    foreach ($checkRootCategory  as $rootCat) {
                        $getUpdatedProductCat[] = in_array($rootCat, $getAllCategories) ? "root" : $rootCat;
                    }

                    $checkedRootCategory = ($getUpdatedProductCat === 'root') ? [] : $getUpdatedProductCat;

                    if ($key = array_search('root', $checkedRootCategory)) {
                        unset($checkedRootCategory[$key]);
                    }

                    if ($checkedRootCategory[0] != 'root') {
                        $productData["categories"] = $checkedRootCategory;
                    }
                }
            }
        }

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

        if (isset($this->templateStore["extraMapping"]["exportAttributeLabel"]) && "true" == $this->templateStore["extraMapping"]["exportAttributeLabel"]) {
            if (!empty($this->templateStore["extraMapping"]["familyVariantFieldName"])) {
                if (array_key_exists($this->templateStore["extraMapping"]["familyVariantFieldName"], $data)) {
                    $productData["family_variant"] = $this->byFamilyvariantCodesByLabel($data[$this->templateStore["extraMapping"]["familyVariantFieldName"]]) ?? '';
                }
            }
        }

        if (isset($this->templateStore["extraMapping"]["exportCategoryLabel"]) && "true" == $this->templateStore["extraMapping"]["exportCategoryLabel"]) {
            if (!array_key_exists($this->templateStore["extraMapping"]["categoryFieldName"], $csvData)) {
                $this->stepExecution->addWarning(
                    "Category header in the CSV file is not defined as the category field value in the template.",
                    [],
                    new DataInvalidItem([])
                );
            } else {
                $category = [];
                $categoryData = null;
                $saperator = isset($this->templateStore["extraMapping"]["multiValueSeperator"]) ? ($this->templateStore["extraMapping"]["multiValueSeperator"]) : null;
                $mvs = !empty($saperator) ? $saperator : ",";

                if (!empty($this->templateStore["extraMapping"]["categoryFieldName"])) {
                    $categoryData = $data[$this->templateStore["extraMapping"]["categoryFieldName"]] ?? null;
                }

                if ($categoryData) {
                    $data = explode($mvs, $categoryData);
                    $result = "'" . implode("', '", $data) . "'";
                    $categories = ($this->byCategoryCodesByLabel($result));
                    $categories = empty($categories) ? [] : array_unique($categories);

                    if (!empty($categories)) {
                        foreach ($categories as $value) {
                            $checkCategory = $this->connectorService->checkParentCategory($value);

                            if ($checkCategory) {
                                $category[] = $value;
                            }
                        }

                        $productData["categories"] = $category;
                    } elseif (empty($category) || empty($categories)) {
                        $this->stepExecution->addWarning(
                            "Categories  " . "'$categoryData'" . "  with labels does not exit in the Akeneo Pim",
                            [],
                            new DataInvalidItem([])
                        );
                    }
                } else {
                    $productData["categories"] = [];
                }
            }
        }

        return $productData;
    }

    public function byFamilyvariantCodesByLabel($familyvariantLabel)
    {
        if (empty($familyvariantLabel)) {
            return [];
        }

        $sql = <<<SQL
        SELECT
        f.code AS code
        FROM pim_catalog_family_variant f
        INNER JOIN 	pim_catalog_family_variant_translation trans ON f.id = trans.foreign_key
        WHERE trans.label IN ('$familyvariantLabel')
        SQL;
        $rows = $this->connection->executeQuery($sql)->fetchAllAssociative();

        if (!empty($rows)) {
            foreach ($rows as $row) {
                $familyvariantLabel = $row["code"];
            }
        }

        return $familyvariantLabel;
    }

    public function byCategoryCodesByLabel($categoryLabel)
    {
        $categoryLabelTranslations = [];

        if (empty($categoryLabel)) {
            return [];
        }

        $sql = <<<SQL
        SELECT
        c.code AS code
        FROM pim_catalog_category c
        INNER JOIN pim_catalog_category_translation trans ON c.id = trans.foreign_key
        WHERE trans.label IN ($categoryLabel)
        SQL;
        $rows = $this->connection->executeQuery($sql)->fetchAllAssociative();
        $categoryLabelTranslations = null;

        if (!empty($rows)) {
            foreach ($rows as $row) {
                $categoryLabelTranslations[] = $row["code"];
            }
        }

        return $categoryLabelTranslations;
    }

    public function countTreesChildrenAction(): array
    {
        $countChildren = $this->countTreesChildrenQuery->execute();

        return array_keys($countChildren);
    }
}
