<?php

declare(strict_types=1);

namespace App\Support;

use App\Models\OperationRun;
use App\Models\PolicyVersion;
use App\Services\Intune\SecretClassificationService;

final class RedactionIntegrity
{
    public static function protectedValueNote(): string
    {
        return 'Protected values are intentionally hidden as [REDACTED]. Secret-only changes remain detectable without revealing the value.';
    }

    public static function supportDiagnosticsNote(): string
    {
        return 'Support diagnostics are default-redacted. Secrets, credentials, raw provider payloads, full response bodies, and unrestricted log excerpts are intentionally excluded.';
    }

    /**
     * @return list<array{path: ?string, reason: string, replacement_text: string}>
     */
    public static function supportDiagnosticsMarkers(): array
    {
        return [
            [
                'path' => 'provider_connection.credential',
                'reason' => 'credential',
                'replacement_text' => '[REDACTED]',
            ],
            [
                'path' => 'stored_reports.payload',
                'reason' => 'raw_payload',
                'replacement_text' => '[REDACTED]',
            ],
            [
                'path' => 'audit_logs.metadata.raw',
                'reason' => 'restricted_log_excerpt',
                'replacement_text' => '[REDACTED]',
            ],
        ];
    }

    public static function noteForPolicyVersion(PolicyVersion $version): ?string
    {
        if (self::fingerprintCount($version->secret_fingerprints) > 0) {
            return self::protectedValueNote();
        }

        return null;
    }

    /**
     * @param  array<string, mixed>  $evidence
     */
    public static function noteForFindingEvidence(array $evidence): ?string
    {
        $notes = self::findingEvidenceNotes($evidence);

        return $notes === [] ? null : implode(' ', $notes);
    }

    public static function noteForRun(OperationRun $run): ?string
    {
        $context = is_array($run->context) ? $run->context : [];
        $integrityNote = data_get($context, 'redaction_integrity.note');

        if (is_string($integrityNote) && trim($integrityNote) !== '') {
            return trim($integrityNote);
        }

        if ((bool) data_get($context, 'redaction_integrity.protected_values_hidden', false)) {
            return self::protectedValueNote();
        }

        return null;
    }

    /**
     * @param  array<string, mixed>|null  $report
     * @return array<int, string>
     */
    public static function verificationNotes(?array $report): array
    {
        if (! is_array($report)) {
            return [];
        }

        if (! self::containsPlaceholderFragment($report)) {
            return [];
        }

        return [self::protectedValueNote()];
    }

    /**
     * @param  array<string, mixed>|null  $fingerprints
     */
    public static function fingerprintCount(?array $fingerprints): int
    {
        if (! is_array($fingerprints)) {
            return 0;
        }

        $count = 0;

        foreach ($fingerprints as $bucket) {
            if (! is_array($bucket)) {
                continue;
            }

            foreach ($bucket as $digest) {
                if (is_string($digest) && trim($digest) !== '') {
                    $count++;
                }
            }
        }

        return $count;
    }

    /**
     * @param  array<string, mixed>  $evidence
     */
    private static function evidenceHasProtectedData(array $evidence): bool
    {
        foreach (['baseline', 'current'] as $side) {
            $fingerprints = data_get($evidence, "{$side}.secret_fingerprints");

            if (is_array($fingerprints) && self::fingerprintCount($fingerprints) > 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param  array<string, mixed>  $evidence
     * @return array<int, string>
     */
    private static function findingEvidenceNotes(array $evidence): array
    {
        $notes = [];

        if (self::evidenceHasProtectedData($evidence)) {
            $notes[] = self::protectedValueNote();
        }

        return array_values(array_unique($notes));
    }

    private static function containsPlaceholderFragment(mixed $value): bool
    {
        if (is_string($value)) {
            return str_contains($value, SecretClassificationService::REDACTED);
        }

        if (! is_array($value)) {
            return false;
        }

        foreach ($value as $item) {
            if (self::containsPlaceholderFragment($item)) {
                return true;
            }
        }

        return false;
    }
}
