<?php

declare(strict_types=1);

namespace Tests\Feature\Concerns;

use App\Models\EvidenceSnapshot;
use App\Models\OperationRun;
use App\Models\ReviewPack;
use App\Models\ManagedEnvironment;
use App\Models\EnvironmentReview;
use App\Models\User;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\ReviewPackStatus;
use App\Support\EnvironmentReviewCompletenessState;
use App\Support\EnvironmentReviewStatus;

trait BuildsGovernanceArtifactTruthFixtures
{
    protected function makeArtifactTruthEvidenceSnapshot(
        ManagedEnvironment $tenant,
        array $snapshotOverrides = [],
        array $summaryOverrides = [],
    ): EvidenceSnapshot {
        $defaults = [
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'status' => EvidenceSnapshotStatus::Active->value,
            'completeness_state' => EvidenceCompletenessState::Complete->value,
            'summary' => array_replace_recursive([
                'dimension_count' => 5,
                'finding_count' => 2,
                'report_count' => 2,
                'operation_count' => 2,
                'missing_dimensions' => 0,
                'stale_dimensions' => 0,
            ], $summaryOverrides),
            'fingerprint' => hash('sha256', 'evidence-'.$tenant->getKey().'-'.microtime()),
            'generated_at' => now(),
        ];

        return EvidenceSnapshot::query()->create(array_replace($defaults, $snapshotOverrides));
    }

    protected function makeStaleArtifactTruthEvidenceSnapshot(
        ManagedEnvironment $tenant,
        array $snapshotOverrides = [],
        array $summaryOverrides = [],
    ): EvidenceSnapshot {
        $snapshot = $this->makeArtifactTruthEvidenceSnapshot($tenant, $snapshotOverrides, $summaryOverrides);

        return $this->restateArtifactTruthEvidenceSnapshot(
            $snapshot,
            EvidenceCompletenessState::Stale,
            array_replace([
                'missing_dimensions' => 0,
                'stale_dimensions' => 2,
            ], $summaryOverrides),
        );
    }

    protected function makePartialArtifactTruthEvidenceSnapshot(
        ManagedEnvironment $tenant,
        array $snapshotOverrides = [],
        array $summaryOverrides = [],
    ): EvidenceSnapshot {
        $snapshot = $this->makeArtifactTruthEvidenceSnapshot($tenant, $snapshotOverrides, $summaryOverrides);

        return $this->restateArtifactTruthEvidenceSnapshot(
            $snapshot,
            EvidenceCompletenessState::Partial,
            array_replace([
                'missing_dimensions' => 1,
                'stale_dimensions' => 0,
            ], $summaryOverrides),
        );
    }

    protected function makeMissingArtifactTruthEvidenceSnapshot(
        ManagedEnvironment $tenant,
        array $snapshotOverrides = [],
        array $summaryOverrides = [],
    ): EvidenceSnapshot {
        $snapshot = $this->makeArtifactTruthEvidenceSnapshot($tenant, $snapshotOverrides, $summaryOverrides);

        return $this->restateArtifactTruthEvidenceSnapshot(
            $snapshot,
            EvidenceCompletenessState::Missing,
            array_replace([
                'dimension_count' => 0,
                'missing_dimensions' => 1,
                'stale_dimensions' => 0,
            ], $summaryOverrides),
        );
    }

    protected function makeArtifactTruthReview(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        array $reviewOverrides = [],
        array $summaryOverrides = [],
    ): EnvironmentReview {
        $snapshot ??= $this->makeArtifactTruthEvidenceSnapshot($tenant);

        $defaults = [
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'evidence_snapshot_id' => (int) $snapshot->getKey(),
            'initiated_by_user_id' => (int) $user->getKey(),
            'status' => EnvironmentReviewStatus::Ready->value,
            'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
            'summary' => array_replace_recursive([
                'publish_blockers' => [],
                'section_state_counts' => [
                    'complete' => 6,
                    'partial' => 0,
                    'missing' => 0,
                    'stale' => 0,
                ],
                'finding_count' => 2,
                'report_count' => 2,
                'operation_count' => 2,
                'section_count' => 6,
            ], $summaryOverrides),
            'fingerprint' => hash('sha256', 'review-'.$tenant->getKey().'-'.microtime()),
            'generated_at' => now(),
        ];

        return EnvironmentReview::query()->create(array_replace($defaults, $reviewOverrides));
    }

    protected function makePartialArtifactTruthReview(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        array $reviewOverrides = [],
        array $summaryOverrides = [],
    ): EnvironmentReview {
        return $this->makeArtifactTruthReview(
            tenant: $tenant,
            user: $user,
            snapshot: $snapshot,
            reviewOverrides: array_replace([
                'status' => EnvironmentReviewStatus::Ready->value,
                'completeness_state' => EnvironmentReviewCompletenessState::Partial->value,
            ], $reviewOverrides),
            summaryOverrides: array_replace_recursive([
                'section_state_counts' => [
                    'complete' => 4,
                    'partial' => 1,
                    'missing' => 1,
                    'stale' => 0,
                ],
            ], $summaryOverrides),
        );
    }

    protected function makeBlockedArtifactTruthReview(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        array $reviewOverrides = [],
        array $summaryOverrides = [],
    ): EnvironmentReview {
        return $this->makeArtifactTruthReview(
            tenant: $tenant,
            user: $user,
            snapshot: $snapshot,
            reviewOverrides: array_replace([
                'status' => EnvironmentReviewStatus::Draft->value,
                'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
            ], $reviewOverrides),
            summaryOverrides: array_replace_recursive([
                'publish_blockers' => ['Resolve the remaining review blocker before publication.'],
            ], $summaryOverrides),
        );
    }

    protected function makeInternalOnlyArtifactTruthReview(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        array $reviewOverrides = [],
        array $summaryOverrides = [],
    ): EnvironmentReview {
        $snapshot ??= $this->makeStaleArtifactTruthEvidenceSnapshot($tenant);

        return $this->makeArtifactTruthReview(
            tenant: $tenant,
            user: $user,
            snapshot: $snapshot,
            reviewOverrides: array_replace([
                'status' => EnvironmentReviewStatus::Ready->value,
                'completeness_state' => EnvironmentReviewCompletenessState::Stale->value,
            ], $reviewOverrides),
            summaryOverrides: array_replace_recursive([
                'section_state_counts' => [
                    'complete' => 5,
                    'partial' => 0,
                    'missing' => 0,
                    'stale' => 1,
                ],
            ], $summaryOverrides),
        );
    }

    protected function makeArtifactTruthReviewPack(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        ?EnvironmentReview $review = null,
        array $packOverrides = [],
        array $summaryOverrides = [],
    ): ReviewPack {
        $snapshot ??= $this->makeArtifactTruthEvidenceSnapshot($tenant);
        $review ??= $this->makeArtifactTruthReview($tenant, $user, $snapshot);

        $defaults = [
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'environment_review_id' => (int) $review->getKey(),
            'evidence_snapshot_id' => (int) $snapshot->getKey(),
            'initiated_by_user_id' => (int) $user->getKey(),
            'status' => ReviewPackStatus::Ready->value,
            'summary' => array_replace_recursive([
                'review_status' => $review->status,
                'review_completeness_state' => $review->completeness_state,
                'finding_count' => 2,
                'report_count' => 2,
                'operation_count' => 2,
                'evidence_resolution' => [
                    'outcome' => 'resolved',
                    'snapshot_id' => (int) $snapshot->getKey(),
                    'snapshot_fingerprint' => (string) $snapshot->fingerprint,
                    'completeness_state' => (string) $snapshot->completeness_state,
                ],
            ], $summaryOverrides),
            'fingerprint' => hash('sha256', 'pack-'.$tenant->getKey().'-'.microtime()),
            'file_disk' => 'exports',
            'file_path' => 'review-packs/'.microtime(true).'.zip',
            'sha256' => hash('sha256', 'pack-file-'.$tenant->getKey().'-'.microtime()),
            'file_size' => 1024,
            'generated_at' => now(),
            'expires_at' => now()->addDays(30),
        ];

        return ReviewPack::query()->create(array_replace($defaults, $packOverrides));
    }

    protected function makeBlockedArtifactTruthReviewPack(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        ?EnvironmentReview $review = null,
        array $packOverrides = [],
        array $summaryOverrides = [],
    ): ReviewPack {
        $review ??= $this->makeBlockedArtifactTruthReview($tenant, $user, $snapshot);
        $snapshot ??= $review->evidenceSnapshot;

        return $this->makeArtifactTruthReviewPack(
            tenant: $tenant,
            user: $user,
            snapshot: $snapshot,
            review: $review,
            packOverrides: array_replace([
                'status' => ReviewPackStatus::Generating->value,
            ], $packOverrides),
            summaryOverrides: array_replace_recursive([
                'evidence_resolution' => [
                    'outcome' => 'blocked',
                ],
            ], $summaryOverrides),
        );
    }

    protected function makeInternalOnlyArtifactTruthReviewPack(
        ManagedEnvironment $tenant,
        User $user,
        ?EvidenceSnapshot $snapshot = null,
        ?EnvironmentReview $review = null,
        array $packOverrides = [],
        array $summaryOverrides = [],
    ): ReviewPack {
        $review ??= $this->makeInternalOnlyArtifactTruthReview($tenant, $user, $snapshot);
        $snapshot ??= $review->evidenceSnapshot;

        return $this->makeArtifactTruthReviewPack(
            tenant: $tenant,
            user: $user,
            snapshot: $snapshot,
            review: $review,
            packOverrides: array_replace([
                'status' => ReviewPackStatus::Ready->value,
            ], $packOverrides),
            summaryOverrides: array_replace_recursive([
                'review_status' => (string) $review->status,
                'review_completeness_state' => (string) $review->completeness_state,
            ], $summaryOverrides),
        );
    }

    protected function makeArtifactTruthRun(
        ManagedEnvironment $tenant,
        string $type,
        array $context = [],
        array $attributes = [],
    ): OperationRun {
        $defaults = [
            'managed_environment_id' => (int) $tenant->getKey(),
            'workspace_id' => (int) $tenant->workspace_id,
            'type' => $type,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Succeeded->value,
            'initiator_name' => 'Artifact Truth Test',
            'context' => $context,
            'summary_counts' => [],
            'failure_summary' => [],
            'started_at' => now()->subMinute(),
            'completed_at' => now(),
        ];

        return OperationRun::factory()->create(array_replace($defaults, $attributes));
    }

    /**
     * @param  array<string, mixed>  $summaryOverrides
     */
    private function restateArtifactTruthEvidenceSnapshot(
        EvidenceSnapshot $snapshot,
        EvidenceCompletenessState $completenessState,
        array $summaryOverrides = [],
    ): EvidenceSnapshot {
        $summary = is_array($snapshot->summary) ? $snapshot->summary : [];

        $summary = array_replace($summary, match ($completenessState) {
            EvidenceCompletenessState::Stale => [
                'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
                'missing_dimensions' => 0,
                'stale_dimensions' => max(1, (int) ($summary['stale_dimensions'] ?? 1)),
            ],
            EvidenceCompletenessState::Partial => [
                'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
                'missing_dimensions' => max(1, (int) ($summary['missing_dimensions'] ?? 1)),
                'stale_dimensions' => 0,
            ],
            EvidenceCompletenessState::Missing => [
                'dimension_count' => (int) ($summary['dimension_count'] ?? 0),
                'missing_dimensions' => max(1, (int) ($summary['missing_dimensions'] ?? 1)),
                'stale_dimensions' => 0,
            ],
            EvidenceCompletenessState::Complete => [
                'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
                'missing_dimensions' => 0,
                'stale_dimensions' => 0,
            ],
        });

        $summary = array_replace_recursive($summary, $summaryOverrides);

        $snapshot->forceFill([
            'completeness_state' => $completenessState->value,
            'summary' => $summary,
        ])->save();

        return $snapshot->fresh();
    }
}
