<?php

declare(strict_types=1);

namespace Leadlion\StockUpdates\Cron;

use Magento\Catalog\Api\Data\BasePriceInterfaceFactory;
use Magento\Catalog\Model\Product\Price\BasePriceStorage;
use Magento\Framework\Exception\LocalizedException;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory as AttributeSetCollectionFactory;
use Monolog\Logger as MonoLogger;
use Monolog\Handler\StreamHandler;
use Monolog\Level;

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

    private $basePriceStorage;
    private $basePriceInterfaceFactory;

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

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

    public function __construct(
        BasePriceStorage $basePriceStorage,
        BasePriceInterfaceFactory $basePriceInterfaceFactory,
        CollectionFactory $collectionFactory,
        AttributeSetCollectionFactory $attributeSetCollectionFactory
    ) {
        $this->basePriceStorage = $basePriceStorage;
        $this->basePriceInterfaceFactory = $basePriceInterfaceFactory;
        $this->collectionFactory = $collectionFactory;
        $this->attributeSetCollectionFactory = $attributeSetCollectionFactory;
    }

    public function execute()
    {
        $monolog = new MonoLogger('carsupreme_prices');
        $monolog->pushHandler(new StreamHandler(BP . '/var/log/carsupreme_prices.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);

        $prices = [];

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

                if ($price < 1) {
                    continue;
                }

                $priceObject = $this->basePriceInterfaceFactory->create()
                    ->setSku($sku)
                    ->setPrice($price)
                    ->setStoreId(0);
                $prices[] = $priceObject;

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

        if (empty($prices)) {
            $logger->info('No products to update.');
            return;
        }

        try {
            $this->basePriceStorage->update($prices);
            $logger->info('Updated ' . count($prices) . ' product prices.');
        } catch (LocalizedException $e) {
            $logger->info('Error updating Carsupreme product prices: ' . $e->getMessage());
        }
    }

    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);
        $priceIndex = array_search('price', $header);

        if ($idIndex === false || $priceIndex === 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 . ', price index: ' . $priceIndex);

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

            $id = trim($data[$idIndex]);
            $price = (float)preg_replace('/[^0-9.]/', '', str_replace(',', '.', $data[$priceIndex]));

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

        fclose($stream);

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

        return $contentFile;
    }
}
