<?php

declare(strict_types=1);

namespace App\Services\Intune;

use Illuminate\Support\Str;

final class SecretClassificationService
{
    public const string REDACTED = '[REDACTED]';

    public const int REDACTION_VERSION = 1;

    /**
     * @var array<int, string>
     */
    private const array PROTECTED_FIELD_NAMES = [
        'access_token',
        'apikey',
        'api_key',
        'authorization',
        'bearer',
        'bearer_token',
        'client_secret',
        'cookie',
        'password',
        'presharedkey',
        'pre_shared_key',
        'private_key',
        'refresh_token',
        'sas_token',
        'secret',
        'set-cookie',
        'shared_secret',
        'token',
    ];

    /**
     * @var array<string, array<int, string>>
     */
    private const array PROTECTED_JSON_POINTERS = [
        'snapshot' => [
            '/wifi/password',
            '/authentication/clientSecret',
        ],
        'assignments' => [],
        'scope_tags' => [],
        'audit' => [],
        'verification' => [],
        'ops_failure' => [],
    ];

    public function protectsField(string $sourceBucket, string $fieldName, ?string $jsonPointer = null): bool
    {
        $fieldName = $this->normalizeFieldName($fieldName);

        if ($fieldName === '') {
            return false;
        }

        $protectedPointers = self::PROTECTED_JSON_POINTERS[$sourceBucket] ?? [];

        if (is_string($jsonPointer) && in_array($jsonPointer, $protectedPointers, true)) {
            return true;
        }

        return in_array($fieldName, self::PROTECTED_FIELD_NAMES, true);
    }

    public function sanitizeAuditString(string $value): string
    {
        return $this->sanitizeMessageLikeString($value, '[REDACTED]');
    }

    public function sanitizeOpsFailureString(string $value): string
    {
        $sanitized = $this->sanitizeMessageLikeString($value, '[REDACTED_SECRET]');
        $sanitized = preg_replace('/(?:\[[A-Z_]+\]|[A-Z0-9._%+\-]+)@[A-Z0-9.\-]+\.[A-Z]{2,}/i', '[REDACTED_EMAIL]', $sanitized) ?? $sanitized;

        return $sanitized;
    }

    private function sanitizeMessageLikeString(string $value, string $replacement): string
    {
        $patterns = [
            '/\bAuthorization\s*:\s*Bearer\s+[A-Za-z0-9\-\._~\+\/]+=*/i',
            '/\bBearer\s+[A-Za-z0-9\-\._~\+\/]+=*/i',
            '/\b[A-Za-z0-9\-_]{20,}\.[A-Za-z0-9\-_]{20,}\.[A-Za-z0-9\-_]{20,}\b/',
        ];

        foreach ($patterns as $pattern) {
            $value = preg_replace($pattern, $replacement, $value) ?? $value;
        }

        foreach (self::PROTECTED_FIELD_NAMES as $fieldName) {
            $quotedPattern = sprintf('/"%s"\s*:\s*"[^"]*"/i', preg_quote($fieldName, '/'));
            $pairPattern = sprintf('/\b%s\b\s*[:=]\s*[^\s,;]+/i', preg_quote($fieldName, '/'));

            $value = preg_replace($quotedPattern, sprintf('"%s":"%s"', $fieldName, $replacement), $value) ?? $value;
            $value = preg_replace($pairPattern, sprintf('%s=%s', $fieldName, $replacement), $value) ?? $value;
        }

        return $value;
    }

    private function normalizeFieldName(string $fieldName): string
    {
        $fieldName = Str::of($fieldName)
            ->replace(['-', ' '], '_')
            ->snake()
            ->lower()
            ->toString();

        return trim($fieldName);
    }
}
