<?php

declare(strict_types=1);

namespace Leadlion\Autogedal\Cron;

use Psr\Log\LoggerInterface;
use Magento\Framework\App\Filesystem\DirectoryList as AppDirectoryList;
use Magento\Framework\Filesystem\DirectoryList;
use Magento\Framework\File\Csv;
use Magento\Framework\Filesystem;
use Magento\Framework\HTTP\Client\Curl;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;

class SaveFeeds
{
    private const FEEDS_DIRECTORY = 'cronimportfeeds';

    private LoggerInterface $logger;
    private DirectoryList $directoryList;
    private Filesystem $filesystem;
    private Curl $curl;

    public function __construct(
        LoggerInterface $logger,
        DirectoryList $directoryList,
        Filesystem $filesystem,
        Curl $curl
    ) {
        $this->logger = $logger;
        $this->directoryList = $directoryList;
        $this->filesystem = $filesystem;
        $this->curl = $curl;
    }

    public function execute(): void
    {
        $feeds = [
            'bare_transversale' => 'https://www.suportbicicleta.ro/feed/products/0d67d127c039f6bf7ad22ecca2c83e98',
            'cutii_portbagaj' => 'https://www.suportbicicleta.ro/feed/products/5ee0c3d912a3eb453ba9597272d27cc0',
            'suporturi_biciclete' => 'https://www.suportbicicleta.ro/feed/products/2376da2334cc06d8a3e5ba053b2ae8ae',
            'schiuri' => 'https://www.suportbicicleta.ro/feed/products/061ca76d790a9030413a92706c3273a0',
            'rrp_portbagaje' => 'https://b2b.aleo.ro/userfiles/CCEAD380-5E19-4246-96CD-5E0BBEB6C560/feeds/CEADE686-459A-4B2F-9921-99CED181A2DF.csv?key=E277C639-7F52-4862-ABE7-D5493AA705A2'
        ];

        try {
            $feedsDirectory = $this->getFeedsDirectory();
            
            $this->logger->info('SaveFeeds cron: Starting feed download process.');

            foreach ($feeds as $feedName => $feedUrl) {
                try {
                    $this->downloadAndSaveFeed($feedName, $feedUrl, $feedsDirectory);
                } catch (\Exception $e) {
                    $this->logger->error(
                        sprintf('SaveFeeds cron: Failed to download feed "%s": %s', $feedName, $e->getMessage())
                    );
                }
            }

            $this->splitAleoFeed($feedsDirectory);

            $this->logger->info('SaveFeeds cron: Feed download process completed successfully.');

        } catch (\Exception $e) {
            $this->logger->error('SaveFeeds cron: Critical error occurred: ' . $e->getMessage());
            throw $e;
        }
    }

    private function getFeedsDirectory(): string
    {
        $mediaPath = $this->directoryList->getPath(AppDirectoryList::MEDIA);
        $feedsPath = $mediaPath . DIRECTORY_SEPARATOR . self::FEEDS_DIRECTORY;

        $mediaWrite = $this->filesystem->getDirectoryWrite(AppDirectoryList::MEDIA);
        
        if (!$mediaWrite->isDirectory(self::FEEDS_DIRECTORY)) {
            $mediaWrite->create(self::FEEDS_DIRECTORY);
            $this->logger->info('SaveFeeds cron: Created feeds directory: ' . $feedsPath);
        }

        return $feedsPath;
    }

    private function downloadAndSaveFeed(string $feedName, string $feedUrl, string $feedsDirectory): void
    {
        $this->logger->info(sprintf('SaveFeeds cron: Downloading feed "%s" from %s', $feedName, $feedUrl));

        $this->curl->setOptions([
            CURLOPT_TIMEOUT => 300,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 5,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; Magento Feed Downloader/1.0)',
            CURLOPT_SSL_VERIFYPEER => false,
        ]);

        $this->curl->get($feedUrl);
        
        if ($this->curl->getStatus() !== 200) {
            throw new LocalizedException(
                __('Failed to download feed "%1". HTTP Status: %2', $feedName, $this->curl->getStatus())
            );
        }

        $feedContent = $this->curl->getBody();
        
        if (empty($feedContent)) {
            throw new LocalizedException(__('Downloaded feed "%1" is empty', $feedName));
        }

        $fileExtension = $this->determineFeedExtension($feedUrl, $feedContent);
        $fileName = $feedName . '.' . $fileExtension;
        $filePath = $feedsDirectory . DIRECTORY_SEPARATOR . $fileName;

        $bytesWritten = file_put_contents($filePath, $feedContent);
        
        if ($bytesWritten === false) {
            throw new FileSystemException(__('Failed to save feed "%1" to file system', $feedName));
        }

        $this->logger->info(sprintf(
            'SaveFeeds cron: Successfully saved feed "%s" (%d bytes) to %s',
            $feedName,
            $bytesWritten,
            $filePath
        ));
    }

    private function splitAleoFeed(string $feedsDirectory): void
    {
        $sourcePath = $feedsDirectory . DIRECTORY_SEPARATOR . 'rrp_portbagaje.csv';

        if (!file_exists($sourcePath)) {
            $this->logger->error('SaveFeeds cron: rrp_portbagaje.csv not found, skipping split.');
            return;
        }

        $handle = fopen($sourcePath, 'r');
        if (!$handle) {
            $this->logger->error('SaveFeeds cron: Cannot open rrp_portbagaje.csv for split.');
            return;
        }

        $header = fgetcsv($handle, 0, ',');
        if (!$header) {
            fclose($handle);
            $this->logger->error('SaveFeeds cron: rrp_portbagaje.csv has no header row.');
            return;
        }

        $categoryIndex = array_search('Categorie', $header);
        if ($categoryIndex === false) {
            fclose($handle);
            $this->logger->error('SaveFeeds cron: Column "Categorie" not found in rrp_portbagaje.csv.');
            return;
        }

        $portbagajeRows     = [];
        $transportCopiiRows = [];
        $gentiRows          = [];

        while (($row = fgetcsv($handle, 0, ',')) !== false) {
            $categorie = trim($row[$categoryIndex] ?? '');
            $parent = str_contains($categorie, '/')
                ? trim(substr($categorie, 0, strpos($categorie, '/')))
                : $categorie;

            if (str_starts_with($parent, 'Cutii portbagaj')) {
                $portbagajeRows[] = $row;
            }
            if (str_starts_with($parent, 'Transport copii')) {
                $transportCopiiRows[] = $row;
            }
            if (str_starts_with($parent, 'Genti, Rucsacuri, Huse')) {
                $gentiRows[] = $row;
            }
        }
        fclose($handle);

        $subFeeds = [
            'b2bportbagajeauto.csv'   => $portbagajeRows,
            'b2bTransportcopii.csv'   => $transportCopiiRows,
            'b2bgentirucsacuri.csv'   => $gentiRows,
        ];

        foreach ($subFeeds as $fileName => $rows) {
            $filePath = $feedsDirectory . DIRECTORY_SEPARATOR . $fileName;
            $fp = fopen($filePath, 'w');
            if (!$fp) {
                $this->logger->error('SaveFeeds cron: Cannot write ' . $fileName);
                continue;
            }
            fputcsv($fp, $header);
            foreach ($rows as $row) {
                fputcsv($fp, $row);
            }
            fclose($fp);
            $this->logger->info(sprintf(
                'SaveFeeds cron: Split feed "%s" saved with %d rows.',
                $fileName,
                count($rows)
            ));
        }
    }

    private function determineFeedExtension(string $url, string $content): string
    {
        $urlExtension = strtolower(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
        
        if (in_array($urlExtension, ['xml', 'csv', 'json', 'txt'])) {
            return $urlExtension;
        }

        $trimmedContent = trim($content);
        
        if (strpos($trimmedContent, '<?xml') === 0 || strpos($trimmedContent, '<') === 0) {
            return 'xml';
        }
        
        if (strpos($trimmedContent, '{') === 0 || strpos($trimmedContent, '[') === 0) {
            return 'json';
        }
        
        if (substr_count($trimmedContent, ',') > 0 && substr_count($trimmedContent, "\n") > 0) {
            return 'csv';
        }
        
        return 'txt';
    }
}
