<?php

declare(strict_types=1);

namespace Tests\Feature\Concerns;

use App\Filament\Resources\ManagedEnvironmentResource\Pages\ListManagedEnvironments;
use App\Models\BackupSet;
use App\Models\RestoreRun;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentTriageReview;
use App\Models\User;
use App\Services\PortfolioTriage\ManagedEnvironmentTriageReviewService;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\BackupHealth\TenantBackupHealthResolver;
use App\Support\RestoreSafety\RestoreResultAttention;
use App\Support\RestoreSafety\RestoreSafetyResolver;
use App\Support\Tenants\TenantRecoveryTriagePresentation;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use InvalidArgumentException;
use Livewire\Livewire;

trait BuildsPortfolioTriageFixtures
{
    /**
     * @return array{0: User, 1: ManagedEnvironment}
     */
    protected function makePortfolioTriageActor(
        string $tenantName = 'Anchor ManagedEnvironment',
        string $role = 'owner',
        string $workspaceRole = 'readonly',
    ): array {
        $tenant = ManagedEnvironment::factory()->create([
            'status' => 'active',
            'name' => $tenantName,
        ]);

        [$user, $tenant] = createMinimalUserWithTenant(
            tenant: $tenant,
            role: $role,
            workspaceRole: $workspaceRole,
        );

        workspaceOverviewSeedQuietTenantTruth($tenant);

        return [$user, $tenant];
    }

    protected function makePortfolioTriagePeer(User $user, ManagedEnvironment $workspaceTenant, string $name): ManagedEnvironment
    {
        $tenant = ManagedEnvironment::factory()->create([
            'status' => 'active',
            'workspace_id' => (int) $workspaceTenant->workspace_id,
            'name' => $name,
        ]);

        createMinimalUserWithTenant(
            tenant: $tenant,
            user: $user,
            role: 'owner',
            workspaceRole: 'readonly',
        );

        workspaceOverviewSeedQuietTenantTruth($tenant);

        return $tenant;
    }

    protected function seedPortfolioBackupConcern(ManagedEnvironment $tenant, string $state): ?BackupSet
    {
        return match ($state) {
            TenantBackupHealthAssessment::POSTURE_ABSENT => null,
            TenantBackupHealthAssessment::POSTURE_STALE => BackupSet::factory()
                ->for($tenant)
                ->staleCompleted()
                ->create([
                    'name' => 'Portfolio stale backup',
                ]),
            TenantBackupHealthAssessment::POSTURE_DEGRADED => BackupSet::factory()
                ->for($tenant)
                ->degradedCompleted()
                ->create([
                    'name' => 'Portfolio degraded backup',
                ]),
            default => workspaceOverviewSeedHealthyBackup($tenant, [
                'name' => 'Portfolio healthy backup',
            ]),
        };
    }

    protected function seedPortfolioRecoveryConcern(
        ManagedEnvironment $tenant,
        string $reason = 'no_history',
        ?BackupSet $backupSet = null,
    ): ?RestoreRun {
        $backupSet ??= workspaceOverviewSeedHealthyBackup($tenant, [
            'name' => 'Portfolio recovery backup',
        ]);

        return match ($reason) {
            'no_history' => null,
            RestoreResultAttention::STATE_FAILED => RestoreRun::factory()
                ->for($tenant)
                ->for($backupSet)
                ->failedOutcome()
                ->create([
                    'completed_at' => now()->subMinutes(10),
                ]),
            RestoreResultAttention::STATE_PARTIAL => RestoreRun::factory()
                ->for($tenant)
                ->for($backupSet)
                ->partialOutcome()
                ->create([
                    'completed_at' => now()->subMinutes(10),
                ]),
            RestoreResultAttention::STATE_COMPLETED_WITH_FOLLOW_UP => RestoreRun::factory()
                ->for($tenant)
                ->for($backupSet)
                ->completedWithFollowUp()
                ->create([
                    'completed_at' => now()->subMinutes(10),
                ]),
            default => RestoreRun::factory()
                ->for($tenant)
                ->for($backupSet)
                ->completedOutcome()
                ->create([
                    'completed_at' => now()->subMinutes(10),
                ]),
        };
    }

    protected function usePortfolioTriageWorkspace(User $user, ManagedEnvironment $tenant): void
    {
        test()->actingAs($user);
        session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
        Filament::setTenant(null, true);
        request()->attributes->remove('tenant_resource.posture_snapshot');
        session()->forget('tables.'.md5(ListManagedEnvironments::class).'_filters');
        session()->forget('tables.'.md5(ListManagedEnvironments::class).'_search');
        session()->forget('tables.'.md5(ListManagedEnvironments::class).'_sort');
    }

    protected function portfolioTriageRegistryList(User $user, ManagedEnvironment $workspaceTenant, array $query = []): mixed
    {
        $this->usePortfolioTriageWorkspace($user, $workspaceTenant);

        $factory = $query !== []
            ? Livewire::withQueryParams($query)->actingAs($user)
            : Livewire::actingAs($user);

        return $factory->test(ListManagedEnvironments::class);
    }

    /**
     * @return array{backup_posture: list<string>, recovery_evidence: list<string>, triage_sort: string|null}
     */
    protected function portfolioReturnFilters(
        array $backupPosture = [],
        array $recoveryEvidence = [],
        array $reviewState = [],
        ?string $triageSort = TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST,
    ): array {
        return [
            'backup_posture' => $backupPosture,
            'recovery_evidence' => $recoveryEvidence,
            'review_state' => $reviewState,
            'triage_sort' => $triageSort,
        ];
    }

    protected function seedPortfolioTriageReview(
        ManagedEnvironment $tenant,
        string $concernFamily,
        string $manualState = ManagedEnvironmentTriageReview::STATE_REVIEWED,
        ?User $actor = null,
        bool $changedFingerprint = false,
    ): ManagedEnvironmentTriageReview {
        $backupHealth = app(TenantBackupHealthResolver::class)->assess($tenant);
        $recoveryEvidence = app(RestoreSafetyResolver::class)->dashboardRecoveryEvidence($tenant);

        $review = match ($manualState) {
            ManagedEnvironmentTriageReview::STATE_REVIEWED => app(ManagedEnvironmentTriageReviewService::class)->markReviewed(
                tenant: $tenant,
                concernFamily: $concernFamily,
                backupHealth: $backupHealth,
                recoveryEvidence: $recoveryEvidence,
                actor: $actor,
            ),
            ManagedEnvironmentTriageReview::STATE_FOLLOW_UP_NEEDED => app(ManagedEnvironmentTriageReviewService::class)->markFollowUpNeeded(
                tenant: $tenant,
                concernFamily: $concernFamily,
                backupHealth: $backupHealth,
                recoveryEvidence: $recoveryEvidence,
                actor: $actor,
            ),
            default => throw new InvalidArgumentException('Unsupported triage review state.'),
        };

        if ($changedFingerprint) {
            $review->forceFill([
                'review_fingerprint' => hash('sha256', sprintf(
                    '%s:%s:%d',
                    $concernFamily,
                    $manualState,
                    (int) $review->getKey(),
                )),
            ])->save();
        }

        request()->attributes->remove('managed_environment_resource.triage_review_snapshot');

        return $review->fresh(['reviewer']);
    }
}
