<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

/**
 * 清理上报 Support Center 的更新结果/失败载荷，避免泄露敏感信息。
 */
final class HostSystemUpdateResultPayloadSanitizer
{
    /**
     * @var list<string>
     */
    private const BLOCKED_MESSAGE_FRAGMENTS = [
        'stack trace',
        'stacktrace',
        'trace:',
        'password',
        'secret',
        'token',
        'authorization:',
        'bearer ',
        '.env',
        'db_password',
        'app_key',
    ];

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>
     */
    public function sanitize(array $payload): array
    {
        return SupportCenterSnapshotSanitizer::sanitize($this->sanitizeValues($payload));
    }

    /**
     * @param  array<string, mixed>  $payload
     * @return array<string, mixed>
     */
    private function sanitizeValues(array $payload): array
    {
        $sanitized = [];

        foreach ($payload as $key => $value) {
            if (! is_string($key)) {
                continue;
            }

            if (is_array($value)) {
                /** @var array<string, mixed> $value */
                $sanitized[$key] = $this->sanitizeValues($value);

                continue;
            }

            if (is_string($value)) {
                $sanitized[$key] = $this->sanitizeString($value, 2000);

                continue;
            }

            if (is_int($value) || is_float($value) || is_bool($value) || $value === null) {
                $sanitized[$key] = $value;
            }
        }

        return $sanitized;
    }

    private function sanitizeString(string $value, int $maxLength): string
    {
        $normalized = trim(preg_replace('/\s+/u', ' ', $value) ?? $value);
        $lower = strtolower($normalized);

        foreach (self::BLOCKED_MESSAGE_FRAGMENTS as $fragment) {
            if (str_contains($lower, $fragment)) {
                return (string) __('dberp.system_update.report.sanitized_message_placeholder');
            }
        }

        if (mb_strlen($normalized) > $maxLength) {
            return mb_substr($normalized, 0, $maxLength).'…';
        }

        return $normalized;
    }
}
