<?php

declare(strict_types=1);

namespace Leadlion\StockUpdates\Cron;

use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory as AttributeSetCollectionFactory;
use Magento\Inventory\Model\SourceItem\Command\Handler\SourceItemsSaveHandler;
use Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockItem;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockStatus;
use Monolog\Logger as MonoLogger;
use Monolog\Handler\StreamHandler;
use Monolog\Level;

class CarsupremeStock
{
    const FEED_URL = "https://carsupreme.ro/2performant_feed.csv";
    const ATTRIBUTE_SET_NAME = 'Paravanturi';

    /**
     * @var CollectionFactory
     */
    protected $collectionFactory;

    /**
     * @var AttributeSetCollectionFactory
     */
    private $attributeSetCollectionFactory;

    /**
     * @var SourceItemInterfaceFactory
     */
    private $sourceItemFactory;

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

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

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

    public function __construct(
        CollectionFactory $collectionFactory,
        AttributeSetCollectionFactory $attributeSetCollectionFactory,
        SourceItemInterfaceFactory $sourceItemFactory,
        SourceItemsSaveHandler $sourceItemsSaveHandler,
        SetDataToLegacyStockItem $setDataToLegacyStockItem,
        SetDataToLegacyStockStatus $setDataToLegacyStockStatus
    ) {
        $this->collectionFactory = $collectionFactory;
        $this->attributeSetCollectionFactory = $attributeSetCollectionFactory;
        $this->sourceItemFactory = $sourceItemFactory;
        $this->sourceItemsSaveHandler = $sourceItemsSaveHandler;
        $this->setDataToLegacyStockItem = $setDataToLegacyStockItem;
        $this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
    }

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

        $attributeSetId = $this->getAttributeSetIdByName(self::ATTRIBUTE_SET_NAME);
        if (!$attributeSetId) {
            $logger->info('Attribute set "' . self::ATTRIBUTE_SET_NAME . '" not found. Aborting.');
            return;
        }

        $feedContent = $this->getFeedContent($logger);
        if (empty($feedContent)) {
            $logger->info('Feed is empty or could not be fetched. Aborting.');
            return;
        }

        $skuFzs[] = array_keys($feedContent);

        $collection = $this->collectionFactory->create()
            ->addAttributeToSelect('sku_fz')
            ->addAttributeToSelect('sku')
            ->addAttributeToFilter('sku_fz', $skuFzs)
            ->addAttributeToFilter('attribute_set_id', $attributeSetId)
            ->addAttributeToFilter('status', Status::STATUS_ENABLED);

        $sourceItems = [];

        foreach ($collection as $product) {
            if (isset($feedContent[$product->getSkuFz()])) {
                $sku = $product->getSku();
                $availability = $feedContent[$product->getSkuFz()]['availability'];

                $isInStock = (strpos($availability, 'out of stock') !== false) ? 0 : 1;
                $qty = $isInStock ? 9999 : 0;

                $sourceItem = $this->sourceItemFactory->create();
                $sourceItem->setData('source_code', 'default');
                $sourceItem->setData('sku', $sku);
                $sourceItem->setData('quantity', $qty);
                $sourceItem->setData('status', $isInStock);
                $sourceItems[] = $sourceItem;

                try {
                    $this->setDataToLegacyStockItem->execute(
                        (string)$sku,
                        (float)$qty,
                        $isInStock
                    );
                    $this->setDataToLegacyStockStatus->execute(
                        (string)$sku,
                        (float)$qty,
                        $isInStock
                    );
                } catch (\Exception $e) {
                    $logger->info('Error saving stock for sku: ' . $sku . ' - ' . $e->getMessage());
                }

                $logger->info('Carsupreme sku: ' . $sku . ' sku_fz: ' . $product->getSkuFz() . ' qty: ' . $qty . ' in_stock: ' . $isInStock);
            }
        }

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

        $logger->info('Done. Updated ' . count($sourceItems) . ' products.');
    }

    private function getAttributeSetIdByName(string $name): ?int
    {
        $collection = $this->attributeSetCollectionFactory->create()
            ->addFieldToFilter('attribute_set_name', $name)
            ->addFieldToFilter('entity_type_id', 4)
            ->setPageSize(1);

        $attributeSet = $collection->getFirstItem();

        return $attributeSet->getId() ? (int)$attributeSet->getId() : null;
    }

    private function getFeedContent($logger): array
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, self::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);
            return [];
        }

        curl_close($ch);

        // use fgetcsv via temp stream to handle multi-line quoted fields
        $stream = fopen('php://temp', 'r+');
        fwrite($stream, $response);
        rewind($stream);

        // parse header
        $header = fgetcsv($stream);
        if (!$header) {
            $logger->info('Could not read CSV header.');
            fclose($stream);
            return [];
        }
        $header = array_map('trim', $header);
        $idIndex = array_search('id', $header);
        $availabilityIndex = array_search('availability', $header);

        if ($idIndex === false || $availabilityIndex === false) {
            $logger->info('Could not find required columns in CSV header. Header: ' . implode(',', $header));
            fclose($stream);
            return [];
        }

        $logger->info('CSV header parsed - id index: ' . $idIndex . ', availability index: ' . $availabilityIndex);

        $contentFile = [];
        while (($data = fgetcsv($stream)) !== false) {
            if (!isset($data[$idIndex]) || !isset($data[$availabilityIndex])) {
                continue;
            }

            $id = trim($data[$idIndex]);
            $availability = strtolower(trim($data[$availabilityIndex]));

            if (!empty($id)) {
                $contentFile[$id] = [
                    'availability' => $availability,
                ];
            }
        }

        fclose($stream);

        $logger->info('Feed parsed: ' . count($contentFile) . ' products found.');

        return $contentFile;
    }
}
