<?php
/**
 * Rejects unsafe custom CSS in global class settings (Law 2 partial).
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

/**
 * Scans Bricks custom CSS strings before they reach the database.
 */
final class CssTextGuard
{
    /**
     * @return array<string, string>
     */
    private const REASONS = [
        'expression'   => 'a CSS expression() call',
        'javascript' => 'a javascript: URL',
        'import'     => 'a remote @import rule',
        'style_break'=> 'a closing </style> tag',
    ];

    public static function rejectionReason(string $css): ?string
    {
        if ($css === '') {
            return null;
        }

        if (preg_match('/expression\s*\(/i', $css) === 1) {
            return self::REASONS['expression'];
        }

        if (preg_match('/javascript\s*:/i', $css) === 1) {
            return self::REASONS['javascript'];
        }

        if (preg_match('/@import\s+(?:url\s*\(\s*)?[\'"]?\s*(?:https?:|\/\/)/i', $css) === 1) {
            return self::REASONS['import'];
        }

        if (preg_match('/<\/style>/i', $css) === 1) {
            return self::REASONS['style_break'];
        }

        return null;
    }

    public static function rejectionMessage(string $reason): string
    {
        return sprintf(
            'I cannot save that custom CSS because it includes %s. Remove it and try again.',
            $reason
        );
    }

    /**
     * @return array{success: false, message: string, error: string}|null
     */
    public static function rejectionResponse(string $css): ?array
    {
        $reason = self::rejectionReason($css);
        if ($reason === null) {
            return null;
        }

        return [
            'success' => false,
            'message' => self::rejectionMessage($reason),
            'error'   => 'unsafe_css',
        ];
    }

    /**
     * @param array<string, mixed> $settings
     * @return array{success: false, message: string, error: string}|null
     */
    public static function validateSettings(array $settings): ?array
    {
        foreach ($settings as $key => $value) {
            if (!is_string($key) || !str_starts_with($key, '_cssCustom')) {
                continue;
            }

            if (!is_string($value) || $value === '') {
                continue;
            }

            $rejection = self::rejectionResponse($value);
            if ($rejection !== null) {
                return $rejection;
            }
        }

        return null;
    }
}
