<?php
declare(strict_types=1);

namespace Leadlion\Autogedal\Model\Job;

use Firebear\ImportExport\Model\Import\Adapter;
use Firebear\ImportExport\Api\Data\JobReplacingInterface;
use Firebear\ImportExport\Model\Import\Attribute;
use Firebear\ImportExport\Model\ImportFactory;
use Firebear\ImportExport\Model\Output\Xslt;
use Firebear\ImportExport\Model\Source\Factory;
use Firebear\ImportExport\Model\Source\Type\File\Config;
use Firebear\ImportExport\Model\JobRepository;
use Magento\Backend\App\ConfigInterface;
use Magento\Backend\Model\Locale\ManagerFactory;
use Magento\Backend\Model\UrlInterface;
use Magento\Framework\App\AreaList;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\ObjectManagerFactory;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\State;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem\File\WriteFactory;
use Magento\Framework\Filesystem\Io\File;
use Magento\Framework\Indexer\IndexerRegistry;
use Magento\Framework\Locale\Resolver;
use Magento\Framework\Registry;
use Magento\Framework\Serialize\Serializer\Serialize as PhpSerializer;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Framework\TranslateInterface;
use Magento\ImportExport\Controller\Adminhtml\ImportResult;
use Magento\ImportExport\Model\History;
use Magento\ImportExport\Model\HistoryFactory;
use Magento\ImportExport\Model\Import;
use Magento\ImportExport\Model\Import\AbstractSource;
use Magento\ImportExport\Model\Import\Entity\AbstractEntity;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator;
use Magento\Indexer\Model\Indexer\CollectionFactory;
use Magento\RemoteStorage\FilesystemFactory;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Import Job Processor.
 * Validate & import jobs launched by cron or by cli command
 * @SuppressWarnings(PHPMD.LongVariable)
 */
#[\AllowDynamicProperties] class Processor extends \Firebear\ImportExport\Model\Job\Processor
{
    /** @var null */
    protected $importFileName = null;

    /** @var bool */
    protected $isValidated = false;

    /** @var string */
    protected $errorMessage = '';

    /**
     * @var
     */
    public $strategy;

    public $errorsCount;

    public $debugMode;

    public $inConsole;

    public $reindex;

    private $indexers = [];

    public $outputModel;
    /**
     * @var JobRepository
     */
    private $jobRepository;

    /**
     * @var \Magento\ImportExport\Model\HistoryFactory
     */
    protected $importHistoryFactory;
    /**
     * @var \Firebear\ImportExport\Model\ImportFactory
     */
    protected $importFactory;
    /**
     * @var ObjectManagerFactory
     */
    protected $objectManagerFactory;
    /**
     * @var \Magento\RemoteStorage\FilesystemFactory
     */
    protected $filesystemFactory;
    /**
     * Object Manager
     *
     * @var \Magento\Framework\ObjectManagerInterface
     */
    protected $objectManager;

    /**
     * @var \Magento\Framework\App\State
     */
    protected $state;
    /**
     * @var \Firebear\ImportExport\Model\Import
     */
    protected $importModel;
    /**
     * @var LoggerInterface
     */
    protected $logger;
    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;
    /**
     * @var StoreManagerInterface
     */
    protected $storeResolver;
    /**
     * @var \Firebear\ImportExport\Api\Data\ImportInterface
     */
    protected $job;
    /**
     * @var \Magento\Framework\Stdlib\DateTime\Timezone
     */
    protected $timezone;
    /**
     * @var UrlInterface
     */
    protected $backendUrl;
    /**
     * @var RequestInterface
     */
    protected $request;

    /**
     * @var History
     */
    protected $importHistoryModel;
    /**
     * Application
     *
     * @var \Magento\Framework\App\AreaList
     */
    protected $areaList;
    /**
     * @var \Magento\Framework\Locale\ResolverInterface
     */
    protected $locale;

    protected $source;

    protected $typeSource;
    /**
     * @var Config
     */
    protected $typeConfig;

    protected $localeLocal;
    /**
     * @var \Magento\Backend\App\ConfigInterface
     */
    protected $backendConfig;
    /**
     * @var \Magento\Backend\Model\Locale\Manager
     */
    protected $manager;

    protected $indCollFactory;

    /**
     * @var IndexerRegistry
     */
    private $indexerRegistry;
    /**
     * @var \Magento\Framework\Filesystem\Io\File
     */
    protected $file;

    /**
     * @var \Magento\Framework\Filesystem\File\WriteFactory
     */
    protected $fileWrite;

    /**
     * @var \Firebear\ImportExport\Model\Source\Factory
     */
    protected $sourceFactory;

    /**
     * @var \Firebear\ImportExport\Model\Source\Platform\Config
     */
    protected $configPlatform;

    /**
     * @var ConsoleOutput
     */
    protected $output;

    /**
     * @var \Magento\Framework\TranslateInterface
     */
    protected $translator;

    /**
     * @var \Magento\Eav\Model\Config
     */
    protected $eavConfig;

    /**
     * @var CacheInterface
     */
    protected $cache;

    /**
     * @var PhpSerializer
     */
    private $phpSerializer;

    /**
     * Processor constructor.
     *
     * @param JobRepository $jobRepository
     * @param ImportFactory $importFactory
     * @param FilesystemFactory $filesystemFactory
     * @param TimezoneInterface $timezone
     * @param RequestInterface $request
     * @param LoggerInterface $logger
     * @param UrlInterface $backendUrl
     * @param ConsoleOutput $output
     * @param Config $typeConfig
     * @param AreaList $areaList
     * @param Resolver $locale
     * @param State $state
     * @param ConfigInterface $backendConfig
     * @param ManagerFactory $manager
     * @param IndexerRegistry $indexerRegistry
     * @param TranslateInterface $translator
     * @param CollectionFactory $indCollFactory
     * @param Xslt $modelOutput
     * @param File $file
     * @param WriteFactory $fileWrite
     * @param Registry $registry
     * @param \Magento\Eav\Model\Config $eavConfig
     * @param Factory $sourceFactory
     * @param \Firebear\ImportExport\Model\Source\Platform\Config $configPlatform
     * @param PhpSerializer $phpSerializer
     * @param CacheInterface $cache
     * @param HistoryFactory $historyFactory
     */
    public function __construct(
        JobRepository                                $jobRepository,
        \Firebear\ImportExport\Model\ImportFactory   $importFactory,
        \Magento\RemoteStorage\FilesystemFactory     $filesystemFactory,
        TimezoneInterface                            $timezone,
        RequestInterface                             $request,
        LoggerInterface                              $logger,
        UrlInterface                                 $backendUrl,
        ConsoleOutput                                $output,
        Config                                       $typeConfig,
        \Magento\Framework\App\AreaList              $areaList,
        \Magento\Framework\Locale\Resolver           $locale,
        \Magento\Framework\App\State                 $state,
        \Magento\Backend\App\ConfigInterface         $backendConfig,
        \Magento\Backend\Model\Locale\ManagerFactory $manager,
        IndexerRegistry                                      $indexerRegistry,
        \Magento\Framework\TranslateInterface                $translator,
        \Magento\Indexer\Model\Indexer\CollectionFactory     $indCollFactory,
        \Firebear\ImportExport\Model\Output\Xslt             $modelOutput,
        \Magento\Framework\Filesystem\Io\File                $file,
        \Magento\Framework\Filesystem\File\WriteFactory      $fileWrite,
        \Magento\Framework\Registry                          $registry,
        \Magento\Eav\Model\Config                            $eavConfig,
        \Firebear\ImportExport\Model\Source\Factory          $sourceFactory,
        \Firebear\ImportExport\Model\Source\Platform\Config  $configPlatform,
        PhpSerializer                                        $phpSerializer,
        CacheInterface $cache,
        \Magento\ImportExport\Model\HistoryFactory           $historyFactory = null
    ) {

        parent::__construct(
            $jobRepository,
            $importFactory,
            $filesystemFactory,
            $timezone,
            $request,
            $logger,
            $backendUrl,
            $output,
            $typeConfig,
            $areaList,
            $locale,
            $state,
            $backendConfig,
            $manager,
            $indexerRegistry,
            $translator,
            $indCollFactory,
            $modelOutput,
            $file,
            $fileWrite,
            $registry,
            $eavConfig,
            $sourceFactory,
            $configPlatform,
            $phpSerializer,
            $cache
        );

        $this->jobRepository = $jobRepository;
        $this->importFactory = $importFactory;
        $this->importHistoryFactory = $historyFactory ?? ObjectManager::getInstance()->create(\Magento\ImportExport\Model\HistoryFactory::class);
        $this->filesystemFactory = $filesystemFactory;
        $this->logger = $logger;
        $this->request = $request;
        $this->backendUrl = $backendUrl;
        $this->timezone = $timezone;
        $this->output = $output;
        $this->typeConfig = $typeConfig;
        $this->locale = $locale;
        $this->areaList = $areaList;
        $this->state = $state;
        $this->localeLocal = null;
        $this->backendConfig = $backendConfig;
        $this->manager = $manager;
        $this->inConsole = 1;
        $this->indexerRegistry = $indexerRegistry;
        $this->indCollFactory = $indCollFactory;
        $this->translator = $translator;
        $this->outputModel = $modelOutput;
        $this->file = $file;
        $this->fileWrite = $fileWrite;
        $this->eavConfig = $eavConfig;
        $this->sourceFactory = $sourceFactory;
        $this->configPlatform = $configPlatform;

        $registry->unregister('isSecureArea');
        $registry->register('isSecureArea', true);
        $this->phpSerializer = $phpSerializer;
        $this->cache = $cache;
    }


    /**
     * Prepare import job object. Load behavior & source data.
     *
     * @param int $jobId
     *
     * @return array
     * @throws LocalizedException
     */
    public function prepareJob($jobId)
    {
        $this->getImportModel()->setLogger($this->logger);
        if (empty($this->getJob()) || $this->getJob()->getId() !== $jobId) {
            $this->setJob($this->jobRepository->getById($jobId));
        }
        $job = $this->getJob();
        $data = [];
        if ($job && $job->getId()) {
            $behaviorData = $job->getBehaviorData();
            $sourceData = $job->getSourceData();
            if (isset($sourceData['language']) && $sourceData['language']) {
                $this->changeLocal($sourceData['language']);
            }
            $iter = [];
            $identicaly = [];
            $mapAttributesData = [];
            foreach ($job->getMap() as $map) {
                $mapAttributesData[$map->getId()] = [
                    'system' => $map->getAttributeId() ? $map->getAttributeId() : $map->getSpecialAttribute(),
                    'import' => $map->getImportCode(),
                    'default' => $map->getDefaultValue()
                ];
                if (!in_array($map->getImportCode(), $iter)) {
                    $iter[] = $map->getImportCode();
                } else {
                    if ($map->getImportCode() != '') {
                        $identicaly[] = [
                            'system' => $map->getAttributeId() ? $map->getAttributeId() : $map->getSpecialAttribute(),
                            'import' => $map->getImportCode()
                        ];
                    }
                }
            }

            $replacingAttributesData = [];
            foreach ($job->getReplacing() as $replacing) {
                $replacingAttributesData[$replacing->getId()] = [
                    JobReplacingInterface::ATTRIBUTE_CODE => $replacing->getAttributeCode(),
                    JobReplacingInterface::ENTITY_TYPE => $replacing->getEntityType(),
                    JobReplacingInterface::TARGET => $replacing->getTarget(),
                    JobReplacingInterface::IS_CASE_SENSITIVE => $replacing->getIsCaseSensitive(),
                    JobReplacingInterface::FIND => $replacing->getFind(),
                    JobReplacingInterface::REPLACE => $replacing->getReplace()
                ];
            }

            $priceRules = [];
            if (!empty($job->getPriceRules())) {
                $priceRules = $this->phpSerializer->unserialize($job->getPriceRules());
            }

            $deliveryTerms = [];
            $deliveryMapping = $this->phpSerializer->unserialize($this->job->getMapping());

            if (!empty($deliveryMapping)) {
                foreach ($deliveryMapping as $key => $field) {
                    if (is_array($field)) {
                        foreach ($field as $mapField) {
                            if (isset($mapField['source_data_attribute_code_system']) &&
                                isset($mapField['source_data_qty']) &&
                                isset($mapField['source_data_delivery_date'])
                            ) {
                                $deliveryTerms[] = $mapField;
                            }
                        }
                    }
                }
            }
            if ($importFile = $this->getImportFile()) {
                if (is_dir($sourceData['file_path']) || $importFile != null) {
                    $sourceData['file_path'] = $importFile;
                }
            }

            $entityName = $this->prepareEntityName($job->getEntity());
            $this->addLogComment(__('Entity %1', $job->getEntity()), $this->output, 'info');

            $data = array_merge(
                ['entity' => $job->getEntity()],
                $behaviorData,
                ['import_source' => $job->getImportSource()],
                $sourceData,
                ['map' => $mapAttributesData],
                ['replacing' => $replacingAttributesData],
                ['price_rules' => $priceRules],
                ['identicaly' => $identicaly],
                ['xslt' => $job->getXslt()],
                ['translate_from' => $job->getTranslateFrom()],
                ['translate_to' => $job->getTranslateTo()],
                ['delivery_terms' => $deliveryTerms]
            );
        }

        if (isset($data['import_images_file_dir']) && !($data['import_images_file_dir'])) {
            unset($data['import_images_file_dir']);
        }

        return $data;
    }

    /**
     * @param $entity
     * @return string
     */
    public function prepareEntityName($entity)
    {
        $map = [
            'catalog_product' => 'products',
            'catalog_category' => 'categories',
            'customer_composite' => 'customers_and_addresses',
            'customer' => 'customer_main',
            'sales_rule' => 'cart_price_rule',
            'search_query' => 'search_terms',
            'content_hierarchy' => 'page_hierarchy'
        ];

        return isset($map[$entity]) ? $map[$entity] : $entity;
    }

    /**
     * @param $data
     * @param $jobId
     *
     * @return bool|int
     * @throws \Exception
     */
    public function dataValidate($data, $jobId)
    {
        try {
            $this->isValidated = $this->validate($data);
        } catch (\Exception $e) {
            $this->getImportModel()->addLogComment($e->getMessage());
            $summary = '<b>' . $e->getMessage() . '</b><br />';
            $importHistoryModel = $this->getImportHistoryModel();
            $importHistoryModel->load($importHistoryModel->getLastItemId());
            $date = $this->getTimezone()->formatDateTime(
                $this->getTimezone()->date(),
                \IntlDateFormatter::MEDIUM,
                \IntlDateFormatter::MEDIUM,
                null,
                null
            );
            $summary .= '<i>' . $date . '</i><br />';
            $summary .= 'Job: #' . $jobId;
            $importHistoryModel->setSummary($summary);
            $importHistoryModel->setExecutionTime(History::IMPORT_FAILED);
            $importHistoryModel->save();
            $this->isValidated = false;
        }
        return $this->isValidated;
    }

    /**
     * Get import history model
     *
     * @return History|mixed
     */
    public function getImportHistoryModel()
    {
        if (!$this->importHistoryModel) {
            $this->importHistoryModel = $this->importHistoryFactory->create();
        }

        return $this->importHistoryModel;
    }
}
