<?php
declare(strict_types=1);

namespace Leadlion\Autogedal\Setup\Patch\Data;

use Magento\Cms\Model\PageFactory;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class ReorderHomepageUspBeforeSlider implements DataPatchInterface
{
    private const PAGE_IDENTIFIER = 'porto_home_12';
    private const SLIDER_BLOCK_ID = '157';
    private const USP_BLOCK_ID = '96';

    /**
     * @var PageFactory
     */
    private $pageFactory;

    public function __construct(PageFactory $pageFactory)
    {
        $this->pageFactory = $pageFactory;
    }

    /**
     * @inheritDoc
     */
    public function apply(): ReorderHomepageUspBeforeSlider
    {
        $page = $this->pageFactory->create();
        $page->load(self::PAGE_IDENTIFIER, 'identifier');

        if (!$page->getId()) {
            return $this;
        }

        $content = (string)$page->getContent();
        $newContent = $this->swapIfNeeded($content, self::SLIDER_BLOCK_ID, self::USP_BLOCK_ID);

        if ($newContent !== $content) {
            $page->setContent($newContent);
            $page->save();
        }

        return $this;
    }

    /**
     * Swaps the two widget blocks in place if $firstBlockId currently appears before $secondBlockId.
     */
    private function swapIfNeeded(string $content, string $firstBlockId, string $secondBlockId): string
    {
        $first = $this->findBlock($content, $firstBlockId);
        $second = $this->findBlock($content, $secondBlockId);

        if ($first === null || $second === null || $first['start'] >= $second['start']) {
            return $content;
        }

        return substr($content, 0, $first['start'])
            . $second['text']
            . substr($content, $first['end'], $second['start'] - $first['end'])
            . $first['text']
            . substr($content, $second['end']);
    }

    /**
     * Finds the widget tag for the given block_id, plus its immediately preceding HTML
     * comment (if any whitespace-only gap separates them), returning text and byte offsets.
     *
     * The widget tag is located first (block_id is unique) and the owning comment is then
     * looked up backwards, to avoid the classic ambiguity of lazily matching "<!--...-->"
     * forward across multiple candidate comments.
     */
    private function findBlock(string $content, string $blockId): ?array
    {
        $widgetPattern = '/\{\{widget[^}]*?block_id="' . preg_quote($blockId, '/') . '"[^}]*?\}\}/s';

        if (!preg_match($widgetPattern, $content, $widgetMatch, PREG_OFFSET_CAPTURE)) {
            return null;
        }

        $widgetStart = $widgetMatch[0][1];
        $widgetEnd = $widgetStart + strlen($widgetMatch[0][0]);
        $blockStart = $widgetStart;

        $before = substr($content, 0, $widgetStart);
        $commentPos = strrpos($before, '<!--');

        if ($commentPos !== false) {
            $commentEndPos = strpos($content, '-->', $commentPos);

            if ($commentEndPos !== false) {
                $commentEndPos += 3;
                $gap = substr($content, $commentEndPos, $widgetStart - $commentEndPos);

                if (preg_match('/^(?:\s|\\\\n)*$/', $gap)) {
                    $blockStart = $commentPos;
                }
            }
        }

        return [
            'text' => substr($content, $blockStart, $widgetEnd - $blockStart),
            'start' => $blockStart,
            'end' => $widgetEnd,
        ];
    }

    /**
     * @inheritDoc
     */
    public function getAliases()
    {
        return [];
    }

    /**
     * @inheritDoc
     */
    public static function getDependencies()
    {
        return [];
    }
}
