<?php

/**
 * ImportanceNormalizerTest.php
 *
 * @since       2026-05-08
 * @category    Library
 * @package     Pdf
 * @author      Nicola Asuni <info@tecnick.com>
 * @copyright   2002-2026 Nicola Asuni - Tecnick.com LTD
 * @license     https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
 * @link        https://github.com/tecnickcom/tc-lib-pdf
 *
 * This file is part of tc-lib-pdf software library.
 */

namespace Test;

use Com\Tecnick\Pdf\CSS\ImportanceNormalizer;
use PHPUnit\Framework\Attributes\DataProvider;

/**
 * Test ImportanceNormalizer CSS declaration normalization
 */
class ImportanceNormalizerTest extends TestUtil
{
    public function testGetAffectedLonghandsExpandsNestedBorderAliases(): void
    {
        $affected = ImportanceNormalizer::getAffectedLonghands('border');

        $this->assertContains('border-width', $affected);
        $this->assertContains('border-style', $affected);
        $this->assertContains('border-color', $affected);
        $this->assertContains('border-top-width', $affected);
        $this->assertContains('border-right-style', $affected);
        $this->assertContains('border-bottom-color', $affected);
        $this->assertContains('border-left-width', $affected);
    }

    public function testNormalizePreservesRegularDeclarations(): void
    {
        $input = 'color: red; font-size: 12px;';
        $result = ImportanceNormalizer::normalize($input);

        $this->assertStringContainsString('color:red;', \str_replace(' ', '', $result));
        $this->assertStringContainsString('font-size:12px;', \str_replace(' ', '', $result));
        $this->assertStringNotContainsString('!important', $result);
    }

    public function testNormalizePreservesImportantFlag(): void
    {
        $input = 'color: red !important; font-size: 12px;';
        $result = ImportanceNormalizer::normalize($input);

        $this->assertStringContainsString('color:red!important;', \str_replace(' ', '', $result));
        $this->assertStringNotContainsString('font-size:12px!important;', \str_replace(' ', '', $result));
    }

    public function testNormalizeBorderShorthandWithoutImportant(): void
    {
        $input = 'border: 1px solid red;';
        $result = ImportanceNormalizer::normalize($input);

        // Should contain the shorthand property
        $this->assertStringContainsString('border:', $result);
        $this->assertStringNotContainsString('!important', $result);
    }

    public function testNormalizeBorderShorthandWithImportant(): void
    {
        $input = 'border: 1px solid red !important;';
        $result = ImportanceNormalizer::normalize($input);

        // The shorthand should have !important
        $this->assertStringContainsString('border:', $result);
        $this->assertStringContainsString('!important', $result);
    }

    public function testNormalizeMixedShorthandAndLonghands(): void
    {
        $input = 'margin: 10px !important; margin-top: 20px;';
        $result = ImportanceNormalizer::normalize($input);

        // Should contain both margin shorthand and the longhand
        $this->assertStringContainsString('margin:', $result);
        $this->assertStringContainsString('margin-top:', $result);
        // Shorthand !important should be preserved
        $this->assertStringContainsString('!important', $result);
    }

    public function testNormalizePaddingShorthandWithImportant(): void
    {
        $input = 'padding: 5px 10px !important;';
        $result = ImportanceNormalizer::normalize($input);

        $this->assertStringContainsString('padding:', $result);
        $this->assertStringContainsString('!important', $result);
    }

    public function testNormalizeEmptyString(): void
    {
        $result = ImportanceNormalizer::normalize('');
        $this->assertSame('', $result);
    }

    public function testNormalizeHandlesWhitespaceAroundImportant(): void
    {
        $input = 'color: blue !  important;';
        $result = ImportanceNormalizer::normalize($input);

        $this->assertStringContainsString('!important', $result);
    }

    public function testNormalizeMultipleImportantDeclarations(): void
    {
        $input = 'color: red !important; background: blue !important; font-size: 14px;';
        $result = ImportanceNormalizer::normalize($input);

        $normalized = \str_replace(' ', '', $result);
        $this->assertStringContainsString('color:red!important;', $normalized);
        $this->assertStringContainsString('background:blue!important;', $normalized);
        $this->assertStringNotContainsString('font-size:14px!important;', $normalized);
    }

    public function testNormalizeHandlesTrailingSemicolon(): void
    {
        $input = 'color: red;';
        $result = ImportanceNormalizer::normalize($input);

        $this->assertStringEndsWith(';', $result);
    }

    public function testNormalizeCaseInsensitive(): void
    {
        $input = 'COLOR: red !IMPORTANT;';
        $result = ImportanceNormalizer::normalize($input);

        // Property should be lowercased
        $this->assertStringContainsString('color:', $result);
        // !important flag should be present (case-insensitive)
        $this->assertStringContainsString('!important', $result);
    }

    public function testNormalizeSkipsMalformedDeclarationSegments(): void
    {
        $input = 'broken; :12px; color: red;';
        $result = ImportanceNormalizer::normalize($input);

        $normalized = \str_replace(' ', '', $result);
        $this->assertSame('color:red;', $normalized);
    }

    public function testNormalizePromotesExistingLonghandWhenShorthandImportantAppearsLater(): void
    {
        $input = 'margin-top: 2px; margin: 10px !important;';
        $result = ImportanceNormalizer::normalize($input);

        $normalized = \str_replace(' ', '', $result);
        $this->assertStringContainsString('margin-top:2px!important;', $normalized);
        $this->assertStringContainsString('margin:10px!important;', $normalized);
    }

    #[DataProvider('realWorldDeclarationsProvider')]
    public function testNormalizeRealWorldDeclarations(string $input, string $expectedProperty): void
    {
        $result = ImportanceNormalizer::normalize($input);

        $this->assertStringContainsString($expectedProperty, $result);
    }

    /** @return array<string, array{0: string, 1: string}> */
    public static function realWorldDeclarationsProvider(): array
    {
        return [
            'button_styling' => [
                'padding: 10px 20px !important; color: white; background: blue;',
                'padding:',
            ],
            'text_emphasis' => [
                'font-weight: bold !important; font-size: 14px;',
                'font-weight:',
            ],
            'border_reset' => [
                'border: none !important; margin: 0;',
                'border:',
            ],
        ];
    }
}
