<?php

declare(strict_types=1);

use App\Support\BackupHealth\BackupFreshnessEvaluation;
use App\Support\BackupHealth\BackupScheduleFollowUpEvaluation;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\PortfolioTriage\PortfolioArrivalContextToken;
use App\Support\PortfolioTriage\ManagedEnvironmentTriageReviewFingerprint;
use Carbon\CarbonImmutable;

afterEach(function (): void {
    CarbonImmutable::setTestNow();
});

function triageFingerprintBackupAssessment(
    int $tenantId,
    string $posture,
    ?string $reason = null,
    string $headline = 'Headline',
    string $supportingMessage = 'Supporting message',
): TenantBackupHealthAssessment {
    return new TenantBackupHealthAssessment(
        tenantId: $tenantId,
        posture: $posture,
        primaryReason: $reason,
        headline: $headline,
        supportingMessage: $supportingMessage,
        latestRelevantBackupSetId: null,
        latestRelevantCompletedAt: now()->subMinutes(15),
        qualitySummary: null,
        freshnessEvaluation: new BackupFreshnessEvaluation(
            latestCompletedAt: now()->subMinutes(15),
            cutoffAt: now()->subHour(),
            isFresh: $posture === TenantBackupHealthAssessment::POSTURE_HEALTHY,
        ),
        scheduleFollowUp: new BackupScheduleFollowUpEvaluation(
            hasEnabledSchedules: false,
            enabledScheduleCount: 0,
            overdueScheduleCount: 0,
            failedRecentRunCount: 0,
            neverSuccessfulCount: 0,
            needsFollowUp: false,
            primaryScheduleId: null,
            summaryMessage: null,
        ),
        healthyClaimAllowed: $posture === TenantBackupHealthAssessment::POSTURE_HEALTHY,
        primaryActionTarget: null,
        positiveClaimBoundary: 'Boundary',
    );
}

it('keeps backup fingerprints deterministic across volatile copy changes', function (): void {
    CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 4, 10, 8, 0, 0, 'UTC'));

    $fingerprints = app(ManagedEnvironmentTriageReviewFingerprint::class);

    $first = $fingerprints->forBackupHealth(triageFingerprintBackupAssessment(
        tenantId: 1,
        posture: TenantBackupHealthAssessment::POSTURE_STALE,
        reason: TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
        headline: 'Original stale backup',
        supportingMessage: 'Original wording',
    ));

    CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 4, 10, 9, 0, 0, 'UTC'));

    $second = $fingerprints->forBackupHealth(triageFingerprintBackupAssessment(
        tenantId: 1,
        posture: TenantBackupHealthAssessment::POSTURE_STALE,
        reason: TenantBackupHealthAssessment::REASON_LATEST_BACKUP_STALE,
        headline: 'Updated stale backup wording',
        supportingMessage: 'Updated wording',
    ));

    expect($first)->not->toBeNull()
        ->and($second)->not->toBeNull()
        ->and($second['fingerprint'])->toBe($first['fingerprint'])
        ->and($second['snapshot'])->toBe($first['snapshot']);
});

it('separates concern families and changes fingerprints when the material concern changes', function (): void {
    $fingerprints = app(ManagedEnvironmentTriageReviewFingerprint::class);

    $backup = $fingerprints->forConcernFamily(
        PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
        triageFingerprintBackupAssessment(
            tenantId: 1,
            posture: TenantBackupHealthAssessment::POSTURE_DEGRADED,
            reason: TenantBackupHealthAssessment::REASON_LATEST_BACKUP_DEGRADED,
        ),
        null,
    );

    $recovery = $fingerprints->forConcernFamily(
        PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        null,
        [
            'overview_state' => 'weakened',
            'reason' => 'failed',
            'latest_relevant_attention_state' => 'failed',
            'summary' => 'Summary A',
            'claim_boundary' => 'Boundary A',
        ],
    );

    $changedRecovery = $fingerprints->forConcernFamily(
        PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
        null,
        [
            'overview_state' => 'weakened',
            'reason' => 'partial',
            'latest_relevant_attention_state' => 'partial',
            'summary' => 'Summary B',
            'claim_boundary' => 'Boundary B',
        ],
    );

    expect($backup)->not->toBeNull()
        ->and($recovery)->not->toBeNull()
        ->and($changedRecovery)->not->toBeNull()
        ->and($backup['concern_family'])->toBe(PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH)
        ->and($recovery['concern_family'])->toBe(PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE)
        ->and($backup['fingerprint'])->not->toBe($recovery['fingerprint'])
        ->and($recovery['fingerprint'])->not->toBe($changedRecovery['fingerprint']);
});

it('only emits fingerprints for current affected-set concerns', function (): void {
    $fingerprints = app(ManagedEnvironmentTriageReviewFingerprint::class);

    expect($fingerprints->forBackupHealth(
        triageFingerprintBackupAssessment(
            tenantId: 1,
            posture: TenantBackupHealthAssessment::POSTURE_HEALTHY,
        ),
    ))->toBeNull()
        ->and($fingerprints->forRecoveryEvidence([
            'overview_state' => 'no_recent_issues_visible',
            'reason' => 'no_recent_issues_visible',
        ]))->toBeNull();
});
