<?php

declare(strict_types=1);

use App\Services\TenantReviews\TenantReviewLifecycleService;
use App\Services\TenantReviews\TenantReviewReadinessGate;
use App\Support\TenantReviewCompletenessState;
use App\Support\TenantReviewStatus;
use App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthPresenter;
use Tests\Feature\Concerns\BuildsGovernanceArtifactTruthFixtures;

uses(BuildsGovernanceArtifactTruthFixtures::class);

it('blocks publication when required review sections are missing from the anchored evidence basis', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $review = composeTenantReviewForTest($tenant, $user, seedTenantReviewEvidence(
        tenant: $tenant,
        permissionPayload: [
            'required_count' => 11,
            'granted_count' => 7,
        ],
        operationRunCount: 0,
    ));

    expect(app(TenantReviewReadinessGate::class)->canPublish($review))->toBeFalse()
        ->and($review->publishBlockers())->not->toBeEmpty();

    $truth = app(ArtifactTruthPresenter::class)->forTenantReview($review);

    expect($truth->artifactExistence)->toBe('created')
        ->and($truth->publicationReadiness)->toBe('blocked')
        ->and($truth->primaryLabel)->toBe('Publication blocked')
        ->and($truth->nextStepText())->toBe('Resolve the review blockers before publication');

    expect(fn () => app(TenantReviewLifecycleService::class)->publish($review, $user, 'Ready for formal publication.'))
        ->toThrow(\InvalidArgumentException::class);
});

it('publishes ready tenant reviews and archives them without mutating the published evidence history', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $review = $this->makeArtifactTruthReview(
        tenant: $tenant,
        user: $user,
        snapshot: $this->makeArtifactTruthEvidenceSnapshot($tenant),
        reviewOverrides: [
            'status' => TenantReviewStatus::Ready->value,
            'completeness_state' => TenantReviewCompletenessState::Complete->value,
        ],
        summaryOverrides: [
            'publish_blockers' => [],
            'section_state_counts' => [
                'complete' => 6,
                'partial' => 0,
                'missing' => 0,
                'stale' => 0,
            ],
        ],
    );

    $published = app(TenantReviewLifecycleService::class)->publish($review, $user, 'Ready for formal publication.');
    $publishedAt = $published->published_at?->toIso8601String();

    expect($published->status)->toBe(TenantReviewStatus::Published->value)
        ->and($published->published_by_user_id)->toBe((int) $user->getKey())
        ->and($publishedAt)->not->toBeNull();

    $publishedTruth = app(ArtifactTruthPresenter::class)->forTenantReview($published);

    $archived = app(TenantReviewLifecycleService::class)->archive($published, $user, 'Superseded by newer review cycle.');
    $archivedTruth = app(ArtifactTruthPresenter::class)->forTenantReview($archived);

    expect($archived->status)->toBe(TenantReviewStatus::Archived->value)
        ->and($archived->archived_at)->not->toBeNull()
        ->and($archived->published_at?->toIso8601String())->toBe($publishedAt)
        ->and($publishedTruth->publicationReadiness)->toBe('publishable')
        ->and($publishedTruth->nextStepText())->toBe('No action needed')
        ->and($archivedTruth->artifactExistence)->toBe('historical_only')
        ->and($archivedTruth->publicationReadiness)->toBe('internal_only')
        ->and($archivedTruth->nextStepText())->toBe('No action needed');
});

it('keeps stale published reviews internal only even when the lifecycle status is published', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $snapshot = seedStaleTenantReviewEvidence($tenant);

    $review = $this->makeArtifactTruthReview(
        tenant: $tenant,
        user: $user,
        snapshot: $snapshot,
        reviewOverrides: [
            'status' => TenantReviewStatus::Published->value,
            'published_at' => now(),
            'published_by_user_id' => (int) $user->getKey(),
            'completeness_state' => TenantReviewCompletenessState::Complete->value,
        ],
        summaryOverrides: [
            'publish_blockers' => [],
            'section_state_counts' => [
                'complete' => 6,
                'partial' => 0,
                'missing' => 0,
                'stale' => 0,
            ],
        ],
    );

    $truth = app(ArtifactTruthPresenter::class)->forTenantReview($review);

    expect($truth->freshnessState)->toBe('stale')
        ->and($truth->publicationReadiness)->toBe('internal_only')
        ->and($truth->primaryLabel)->toBe('Internal only')
        ->and($truth->nextStepText())->toBe('Refresh the evidence basis before publishing this review');
});

it('downgrades structurally ready reviews with partial evidence to internal only', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');
    $snapshot = seedPartialTenantReviewEvidence($tenant);

    $review = $this->makeArtifactTruthReview(
        tenant: $tenant,
        user: $user,
        snapshot: $snapshot,
        reviewOverrides: [
            'status' => TenantReviewStatus::Ready->value,
            'completeness_state' => TenantReviewCompletenessState::Complete->value,
        ],
        summaryOverrides: [
            'publish_blockers' => [],
            'section_state_counts' => [
                'complete' => 6,
                'partial' => 0,
                'missing' => 0,
                'stale' => 0,
            ],
        ],
    );

    $truth = app(ArtifactTruthPresenter::class)->forTenantReview($review);

    expect($truth->contentState)->toBe('partial')
        ->and($truth->freshnessState)->toBe('current')
        ->and($truth->publicationReadiness)->toBe('internal_only')
        ->and($truth->primaryLabel)->toBe('Internal only')
        ->and($truth->nextStepText())->toBe('Complete the evidence basis before publishing this review');
});
