<?php

declare(strict_types=1);

/**
 * @author Amasty Team
 * @copyright Copyright (c) Amasty (https://www.amasty.com)
 * @package Image Optimizer for Magento 2 (System)
 */

namespace Amasty\ImageOptimizer\Model\Output;

use Amasty\ImageOptimizer\Model\LazyConfigProvider;
use Amasty\ImageOptimizer\Model\OptionSource\ReplaceStrategies;
use Amasty\ImageOptimizer\Model\Output\ReplaceConfig\ReplaceConfig;
use Amasty\ImageOptimizer\Model\Output\ReplaceConfig\ReplaceConfigFactory;
use Amasty\PageSpeedTools\Model\Image\ImagesDataByPattern;
use Amasty\PageSpeedTools\Model\Image\ReplacePatternGroupsPool;
use Amasty\PageSpeedTools\Model\Image\ReplacerCompositeInterface;
use Amasty\PageSpeedTools\Model\Image\Utils\ParsedImagesStorage;
use Amasty\PageSpeedTools\Model\Image\Utils\PathsResolver;
use Amasty\PageSpeedTools\Model\Output\OutputProcessorInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\DataObject;

class ImageReplaceProcessor implements OutputProcessorInterface
{
    public const REPLACE_PATTERNS_GROUP_KEY = 'image_optimizer';

    /**
     * @var ReplaceConfig|null
     */
    private ?ReplaceConfig $replaceConfig = null;

    public function __construct(
        private readonly LazyConfigProvider $lazyConfigProvider,
        private readonly ReplacerCompositeInterface $imageReplacer,
        private readonly ReplaceConfigFactory $replaceConfigFactory,
        private readonly ReplacePatternGroupsPool $replacePatternsResolver, // @deprecated
        private readonly PathsResolver $imagePathsResolver, // @deprecated
        private ?ParsedImagesStorage $parsedImagesStorage = null // TODO move to not optional
    ) {
        $this->parsedImagesStorage ??= ObjectManager::getInstance()->get(ParsedImagesStorage::class);
    }

    public function process(string &$output): bool
    {
        if ($this->getLazyConfig()->getData('is_lazy')) {
            return true;
        }

        $this->processImages($output);

        return true;
    }

    public function processImages(string &$output)
    {
        $replaceStrategy = $this->getReplaceConfig()->getData(ReplaceConfig::REPLACE_STRATEGY);
        if ($replaceStrategy !== ReplaceStrategies::NONE) {
            foreach ($this->parsedImagesStorage->getImagesDataByPatterns() as $imagesDataByPattern) {
                $output = $this->modifyOutputByPattern($output, $imagesDataByPattern);
            }
        }
    }

    protected function getLazyConfig(): DataObject
    {
        return $this->lazyConfigProvider->get();
    }

    protected function getReplaceConfig(): DataObject
    {
        if ($this->replaceConfig === null) {
            $this->replaceConfig = $this->replaceConfigFactory->create();
        }

        return $this->replaceConfig;
    }

    private function modifyOutputByPattern(string $output, ImagesDataByPattern $imagesData): string
    {
        $replacePattern = $imagesData->getReplacePattern();
        $resolvedImages = $imagesData->getResolvedImages();

        foreach ($resolvedImages as $imageData) {
            $replaceImagesIgnoreList = $this->getReplaceConfig()
                ->getData(ReplaceConfig::REPLACE_IMAGES_IGNORE_LIST);
            $image = $imageData[ImagesDataByPattern::IMAGE_STRING_WITH_TAG];
            $imgPaths = $imageData[ImagesDataByPattern::IMG_PATHS];

            if ($this->skipIfContain($image, $replaceImagesIgnoreList)) {
                continue;
            }

            foreach ($imgPaths as $imgPath) {
                $newImg = $this->imageReplacer->replace(
                    $replacePattern,
                    $image,
                    $imgPath
                );
                $output = str_replace($image, $newImg, $output);
                $image = $newImg;
            }
        }

        return $output;
    }

    private function skipIfContain(string $searchString, array $list): bool
    {
        $skip = false;
        foreach ($list as $item) {
            if (strpos($searchString, $item) !== false) {
                $skip = true;
                break;
            }
        }

        return $skip;
    }
}
