<?php

namespace Leadlion\StockUpdates\Cron;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\Framework\Serialize\Serializer\Json;
use Magento\Catalog\Model\Product\Action;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Inventory\Model\SourceItem\Command\Handler\SourceItemsSaveHandler;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockItem;
use Magento\Framework\App\ResourceConnection;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockStatus;
use Monolog\Logger as MonoLogger;
use Monolog\Handler\StreamHandler;
use Monolog\Level;

class PtcStock
{
    const PTC_FEED_URL = "https://erp.ptc-auto.ro/feed/products_qty_price_feed_4.csv?access_token=b82cd663-0bf8-49d8-aa42-dd74b539fcec";
    const JOB_ID = 54181;

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;

    /**
     * @var ScopeConfigInterface|Config
     */
    protected $config;
    /**
     * @var LoggerInterface
     */
    protected $logger;
    /**
     * @var CollectionFactory
     */
    protected $collectionFactory;
    /**
     * @var \Magento\InventoryApi\Api\SourceItemsSaveInterface
     */
    private $sourceItemsSaveInterface;
    /**
     * @var SourceItemInterfaceFactory
     */
    private $sourceItemFactory;
    /**
     * @var ProductRepositoryInterface
     */
    private $productRepository;
    /**
     * @var Context
     */
    private $context;

    /**
     * @var StockRegistryInterface
     */
    protected $stockRegistry;

    /**
     * @var Json
     */
    protected $serialize;

    /**
     * @var Action
     */
    private $productAction;
    
    /**
     * @var SourceItemsSaveHandler
     */
    private $sourceItemsSaveHandler;

    /**
     * @var SetDataToLegacyStockItem
     */
    private $setDataToLegacyStockItem;
    
    /**
     * @var SetDataToLegacyStockStatus
     */
    private $setDataToLegacyStockStatus;

    /**
     * ProcessProducts constructor.
     * @param State $state
     * @param Config $config
     * @param Handler $handler
     * @param CollectionFactory $collectionFactory
     */
    public function __construct(
        ScopeConfigInterface       $config,
        CollectionFactory          $collectionFactory,
        SourceItemsSaveInterface   $sourceItemsSaveInterface,
        SourceItemInterfaceFactory $sourceItemFactory,
        ProductRepositoryInterface $productRepository,
        Context                    $context,
        StockRegistryInterface     $stockRegistry,
        Json $serialize,
        Action $productAction,
        SourceItemsSaveHandler $sourceItemsSaveHandler,
        SetDataToLegacyStockItem $setDataToLegacyStockItem,
        ResourceConnection $resourceConnection,
        SetDataToLegacyStockStatus $setDataToLegacyStockStatus
    ) {
        $this->config = $config;
        $this->collectionFactory = $collectionFactory;
        $this->sourceItemsSaveInterface = $sourceItemsSaveInterface;
        $this->sourceItemFactory = $sourceItemFactory;
        $this->productRepository = $productRepository;
        $this->context = $context;
        $this->stockRegistry = $stockRegistry;
        $this->serialize = $serialize;
        $this->productAction = $productAction;
        $this->sourceItemsSaveHandler = $sourceItemsSaveHandler;
        $this->setDataToLegacyStockItem = $setDataToLegacyStockItem;
        $this->resourceConnection = $resourceConnection;
        $this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
    }

    public function execute()
    {
        $monolog = new MonoLogger('ptc_stock');
        $monolog->pushHandler(new StreamHandler(BP . '/var/log/ptc_stock.log', Level::Debug));
        $logger = $monolog;

        $feedContent = $this->getFeedContent($logger);
        
        $sourceItems = [];
        $skuFzs[] = array_keys($feedContent);
        $dataForSkuFz = [];

        $importedSkus = $this->getImportedSkus(self::JOB_ID);

        //return all products by sku_fz
        $collection = $this->collectionFactory->create()
            ->addAttributeToSelect('sku_fz')
            ->addAttributeToSelect('sku')
            ->addAttributeToSelect('manufacturer')
            ->addAttributeToFilter('sku_fz', $skuFzs)
            ->addAttributeToFilter('attribute_set_id', ['neq' => 65])
            ->addAttributeToFilter('status', Status::STATUS_ENABLED);

        foreach ($collection as $product) {
            if (isset($feedContent[$product->getSkuFz()])) {
                $sku = $product->getSku();
                $stockInfo = $feedContent[$product->getSkuFz()];
                $logger->info('PTC $item: '.$sku);
                $qty = $stockInfo[1];

                $dataForSkuFz[] = [
                    'job_id' => self::JOB_ID,
                    'sku' => $product->getSkuFz(),
                    'qty' => $qty
                ];

                $logger->info('$product sku: ' .$product->getData('sku').' sku_fz: '. $product->getData('sku_fz'). ' qty: '. $qty);

                $isInStock = 1;

                $sourceItem = $this->sourceItemFactory->create();
                $sourceItem->setData('source_code', 'default');
                $sourceItem->setData('sku', $product->getData('sku'));
                $sourceItem->setData('quantity', $qty);
                $sourceItem->setData('status', $isInStock);
                $sourceItems[] = $sourceItem;
                
                try {
                    $this->setDataToLegacyStockItem->execute(
                        (string)$product->getData('sku'),
                        (float)$qty,
                        $isInStock
                    );
                    $this->setDataToLegacyStockStatus->execute(
                        (string)$product->getData('sku'),
                        (float)$qty,
                        $isInStock
                    );
                } catch (\Exception $e) {
                    $logger->info('(stockRegistry) cant save stock $product sku: ' .$product->getData('sku').$e->getMessage());
                }
            }
        }

        if (!empty($sourceItems)) {
            $this->sourceItemsSaveHandler->execute($sourceItems);
        }

        // put la comanda products which are not in feed logic
        if (!empty($importedSkus)) {
            foreach ($importedSkus as $key => $info) {
                if (!isset($feedContent[$info['sku']])) {
                    $collection = $this->collectionFactory->create()
                        ->addAttributeToSelect('sku_fz')
                        ->addAttributeToSelect('sku')
                        ->addAttributeToSelect('manufacturer')
                        ->addAttributeToFilter('sku_fz', $info['sku'])
                        ->addAttributeToFilter('status', Status::STATUS_ENABLED);
                    $sourceItems = [];

                    foreach ($collection as $product) {
                        $isInStock = 1;
                        $qty = 0;

                        $sourceItem = $this->sourceItemFactory->create();
                        $sourceItem->setData('source_code', 'default');
                        $sourceItem->setData('sku', $product->getData('sku'));
                        $sourceItem->setData('quantity', $qty);
                        $sourceItem->setData('status', $isInStock);
                        $sourceItems[] = $sourceItem;
                        
                        try {
                            $this->setDataToLegacyStockItem->execute(
                                (string)$product->getData('sku'),
                                (float)$qty,
                                $isInStock
                            );
                            $this->setDataToLegacyStockStatus->execute(
                                (string)$product->getData('sku'),
                                (float)$qty,
                                $isInStock
                            );
                        } catch (\Exception $e) {
                            $logger->info('(stockRegistry) cant save stock $product sku: ' .$product->getData('sku').$e->getMessage());
                        }
                    }
                    if (!empty($sourceItems)) {
                        $this->sourceItemsSaveHandler->execute($sourceItems);
                    }
                }
            }
            $this->deleteImportedSku(self::JOB_ID);
        }

        if (!empty($dataForSkuFz)) {
            $this->resourceConnection->getConnection()->insertOnDuplicate(
                'leadlion_imported_skus',
                $dataForSkuFz
            );
        }
        $logger->info('Done');
    }

    private function deleteImportedSku($jobId)
    {
        $connection = $this->resourceConnection->getConnection();
        $oosProdTable = $this->resourceConnection->getTableName('leadlion_imported_skus');

        $connection->delete(
            $oosProdTable,
            ['job_id = ?' => $jobId]
        );
    }

    private function getImportedSkus($jobId)
    {
        $connection = $this->resourceConnection->getConnection();
        $oosProdTable = $this->resourceConnection->getTableName('leadlion_imported_skus');

        $select = $connection->select();
        $select->from(
            ['e' => $oosProdTable],
            ['id', 'job_id', 'sku','qty']
        )->where(
            'e.job_id = ?',
            $jobId
        );
        return $connection->fetchAll($select);
    }
    
    private function getFeedContent($logger)
    {
        /*
            $data[0] - SKU
            $data[1] - Quantity
            $data[2] - Price
            $data[3] - List Price
            $data[4] - Name
        */
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, self::PTC_FEED_URL);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            $logger->info('Error when reading the file:' . curl_error($ch));
            curl_close($ch);
            exit;
        }

        curl_close($ch);

        $data = [];
        $lines = explode(PHP_EOL, $response);
        foreach ($lines as $line) {
            $data[] = str_getcsv($line);
        }

        $data = array_filter($data);
        
        $contentFile = [];
        foreach ($data as $key => $info) {
            $contentFile[$info[0]] = $info;
        }
        
        return $contentFile;
    }
}
