<?php

declare(strict_types=1);

namespace Autogedal\LegalGuarantee\Setup\Patch\Data;

use Magento\Catalog\Model\Product;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Sql\Expression;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class LimitWarrantyToTwoYears implements DataPatchInterface
{
    private const WARRANTY_ATTRIBUTES = ['garantie', 'auto_warranty_bare'];

    private const WARRANTY_LIMITS = [
        '2'       => '^([3-9]|[1-9][0-9]+)$',
        '2 ani'   => '^([3-9]|[1-9][0-9]+) ani$',
        '24 luni' => '^(2[5-9]|[3-9][0-9]|[1-9][0-9]{2,}) luni$',
    ];

    private const PRODUCT_TEXT_ATTRIBUTES = ['description', 'short_description', 'meta_title', 'meta_description'];

    private const PRODUCT_TEXT_TABLES = ['catalog_product_entity_text', 'catalog_product_entity_varchar'];

    private const CONTENT_COLUMNS = [
        'cms_block'                    => 'content',
        'cms_page'                     => 'content',
        'tm_blog_post'                 => 'content',
        'catalog_category_entity_text' => 'value',
        'checkout_agreement'           => 'content',
    ];

    private const WARRANTY_TEXT_FILTER = [['like' => '%garan%'], ['like' => '%guarant%']];

    private const REPLACEMENTS = [
        'Garantie: 3 ani' => 'Garantie: 2 ani',
        'Garantie 3 ani' => 'Garantie 2 ani',
        'garantie 3 ani' => 'garantie 2 ani',
        'garantie de 3 ani' => 'garantie de 2 ani',
        '3 ani garantie' => '2 ani garantie',
        'Garantie 5 ani' => 'Garantie 2 ani',
        'garantie 5 ani' => 'garantie 2 ani',
        'valabila <strong>5 ani' => 'valabila <strong>2 ani',
        'valabila 5 ani' => 'valabila 2 ani',
        'valabila 60 de luni' => 'valabila 24 de luni',
        'valabila 60 luni' => 'valabila 24 luni',
        'valabila 36 de luni' => 'valabila 24 de luni',
        'producatorul Italian este de 36 de luni' => 'producatorul Italian este de 24 de luni',
        'In functie de produsul ales, beneficezi de o garantie valabila intre 24 si 60 de luni.'
            => 'Beneficiezi de o garantie valabila 24 de luni.',
        '<h3>24 - 60 Luni</h3>' => '<h3>24 Luni</h3>',
        '<h3>24 – 60</h3>' => '<h3>24</h3>',
        '24 – 60 Luni Garantie' => '24 Luni Garantie',
        '24 - 60 luni' => '24 luni',
        'In functie de categoria si brand-ul produselor, te bucuri de' => 'Te bucuri de',
        '<b>garantie</b> cuprinsa intre <b>24 si 60 de luni</b>' => '<b>garantie</b> de <b>24 de luni</b>',
        'Garantia oferita este de 60 de luni.' => 'Garantia oferita este de 24 de luni.',
        'Garantia standard este de 2 ani, dar anumite branduri premium ofera garantii extinse, de pana la 5 ani.'
            => 'Garantia este de 2 ani.',
        'însoțite de garanții cuprinse între 24 și 60 de luni' => 'însoțite de garanție de 24 de luni',
        'Garanție extinsă 24–60 de luni' => 'Garanție de 24 de luni',
        'În funcție de categorie și brand, produsele AutoGedal beneficiază de garanții cuprinse între 24 și 60 de luni.'
            => 'Produsele AutoGedal beneficiază de garanție de 24 de luni.',
        'beneficiază de o garanție cuprinsă între 24 și 60 de luni, în funcție de categoria de produs și de producător.'
            => 'beneficiază de o garanție de 24 de luni.',
        'variaza in functie de fiecare produs, ea fiind cuprinsa intre 24 si 60 de luni,' => 'este de 24 de luni,',
        'variaza in functie de fiecare produs , ea fiind cuprinsa intre 24 si 36 de luni.' => 'este de 24 de luni.',
        'afisate in site, este cuprinsa intre 24 si 36 luni,' => 'afisate in site este de 24 de luni,',
        'garanție de la 24 la 60 de luni' => 'garanție de 24 de luni',
        'garanție mare, de 3 ani' => 'garanție de 2 ani',
        'garanție de 3 ani' => 'garanție de 2 ani',
        'Garanție: 5 ani' => 'Garanție: 2 ani',
        'În funcție de brand și efectuarea unui montaj autorizat, garanția poate ajunge la 5 ani.'
            => 'Garanția oferită este de 2 ani.',
    ];

    public function __construct(
        private readonly ModuleDataSetupInterface $moduleDataSetup
    ) {
    }

    public function apply(): self
    {
        $connection = $this->moduleDataSetup->getConnection();

        $this->limitWarrantyAttributes($connection);
        $this->replaceProductTexts($connection);

        foreach (self::CONTENT_COLUMNS as $table => $column) {
            $this->replaceText($connection, $table, $column);
        }

        return $this;
    }

    private function limitWarrantyAttributes(AdapterInterface $connection): void
    {
        $attributeIds = $this->getProductAttributeIds($connection, self::WARRANTY_ATTRIBUTES);
        if (!$attributeIds) {
            return;
        }

        $table = $this->moduleDataSetup->getTable('catalog_product_entity_varchar');
        foreach (self::WARRANTY_LIMITS as $limit => $pattern) {
            $connection->update(
                $table,
                ['value' => $limit],
                ['attribute_id IN (?)' => $attributeIds, 'value REGEXP ?' => $pattern]
            );
        }
    }

    private function replaceProductTexts(AdapterInterface $connection): void
    {
        $attributeIds = $this->getProductAttributeIds($connection, self::PRODUCT_TEXT_ATTRIBUTES);
        if (!$attributeIds) {
            return;
        }

        foreach (self::PRODUCT_TEXT_TABLES as $table) {
            $this->replaceText($connection, $table, 'value', ['attribute_id IN (?)' => $attributeIds]);
        }
    }

    private function replaceText(AdapterInterface $connection, string $table, string $column, array $where = []): void
    {
        $table = $this->moduleDataSetup->getTable($table);
        if (!$connection->isTableExists($table)) {
            return;
        }

        $quotedColumn = $connection->quoteIdentifier($column);
        $expression = $quotedColumn;
        foreach (self::REPLACEMENTS as $search => $replace) {
            $expression = sprintf(
                'REPLACE(%s, %s, %s)',
                $expression,
                $connection->quote($search),
                $connection->quote($replace)
            );
        }

        $where[] = $connection->prepareSqlCondition($quotedColumn, self::WARRANTY_TEXT_FILTER);

        $connection->update($table, [$column => new Expression($expression)], $where);
    }

    private function getProductAttributeIds(AdapterInterface $connection, array $codes): array
    {
        $select = $connection->select()
            ->from(['attribute' => $this->moduleDataSetup->getTable('eav_attribute')], ['attribute_id'])
            ->join(
                ['entity_type' => $this->moduleDataSetup->getTable('eav_entity_type')],
                'entity_type.entity_type_id = attribute.entity_type_id',
                []
            )
            ->where('entity_type.entity_type_code = ?', Product::ENTITY)
            ->where('attribute.attribute_code IN (?)', $codes);

        return array_map('intval', $connection->fetchCol($select));
    }

    public static function getDependencies(): array
    {
        return [];
    }

    public function getAliases(): array
    {
        return [];
    }
}
