<?php
/**
 * Rejects Bricks code-execution payloads on every write path (Law 2).
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

/**
 * Blocks executeCode settings and never generates Bricks code signatures.
 */
final class BricksCodeGuard
{
    /**
     * Bricks settings keys that enable arbitrary PHP/JS execution.
     *
     * @var string[]
     */
    private const FORBIDDEN_KEYS = [
        'executeCode',
        'codeSignature',
    ];

    /**
     * Returns a short label when the payload carries forbidden code, or null.
     *
     * @param mixed $value
     */
    public static function rejectionReason(mixed $value): ?string
    {
        return self::scan($value);
    }

    /**
     * @param array<string, mixed> $settings
     * @return array{success: false, message: string, error: string}|null
     */
    public static function validateSettings(array $settings): ?array
    {
        return self::rejectionResponse($settings);
    }

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

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

    public static function rejectionMessage(string $reason): string
    {
        return sprintf(
            'I cannot save Bricks code execution settings (%s). Remove it and try again.',
            $reason
        );
    }

    /**
     * @param mixed $value
     */
    private static function scan(mixed $value): ?string
    {
        if (is_array($value)) {
            foreach ($value as $key => $nested) {
                if (is_string($key) && in_array($key, self::FORBIDDEN_KEYS, true)) {
                    return $key;
                }

                $nestedReason = self::scan($nested);
                if ($nestedReason !== null) {
                    return $nestedReason;
                }
            }
        }

        return null;
    }
}
