<?php

declare(strict_types=1);

use App\Filament\Pages\Operations\TenantlessOperationRunViewer;
use App\Models\OperationRun;
use App\Models\SupportRequest;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\OperationRunLinks;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Facades\Filament;
use Livewire\Livewire;

uses(\Illuminate\Foundation\Testing\RefreshDatabase::class);

function operationSupportRequestComponent(User $user, OperationRun $run): \Livewire\Features\SupportTesting\Testable
{
    test()->actingAs($user);
    Filament::setTenant(null, true);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $run->workspace_id);

    return Livewire::actingAs($user)->test(TenantlessOperationRunViewer::class, ['run' => $run]);
}

function operationSupportRequestHeaderActions(\Livewire\Features\SupportTesting\Testable $component): array
{
    $instance = $component->instance();

    if ($instance->getCachedHeaderActions() === []) {
        $instance->cacheInteractsWithHeaderActions();
    }

    return $instance->getCachedHeaderActions();
}

function operationSupportRequestHeaderPrimaryNames(\Livewire\Features\SupportTesting\Testable $component): array
{
    return collect(operationSupportRequestHeaderActions($component))
        ->reject(static fn ($action): bool => $action instanceof ActionGroup)
        ->map(static fn ($action): ?string => $action instanceof Action ? $action->getName() : null)
        ->filter()
        ->values()
        ->all();
}

function operationSupportRequestHeaderMoreActionNames(\Livewire\Features\SupportTesting\Testable $component): array
{
    $moreGroup = collect(operationSupportRequestHeaderActions($component))
        ->first(static fn ($action): bool => $action instanceof ActionGroup && $action->getLabel() === 'More');

    return collect($moreGroup?->getActions() ?? [])
        ->map(static fn ($action): ?string => $action instanceof Action ? $action->getName() : null)
        ->filter()
        ->values()
        ->all();
}

function operationSupportRequestHeaderMoreAction(\Livewire\Features\SupportTesting\Testable $component, string $name): ?Action
{
    $moreGroup = collect(operationSupportRequestHeaderActions($component))
        ->first(static fn ($action): bool => $action instanceof ActionGroup && $action->getLabel() === 'More');

    $action = collect($moreGroup?->getActions() ?? [])
        ->first(static fn ($action): bool => $action instanceof Action && $action->getName() === $name);

    return $action instanceof Action ? $action : null;
}

it('creates a run-scoped support request from the tenantless operation viewer', function (): void {
    $tenant = ManagedEnvironment::factory()->create(['name' => 'Contoso Support ManagedEnvironment']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'operator');

    $run = OperationRun::factory()
        ->forTenant($tenant)
        ->create([
            'type' => OperationRunType::BaselineCompare->value,
            'status' => OperationRunStatus::Completed->value,
            'outcome' => OperationRunOutcome::Failed->value,
            'summary_counts' => [
                'total' => 0,
                'processed' => 0,
            ],
            'failure_summary' => [[
                'message' => 'Run failed after provider validation.',
            ]],
            'completed_at' => now()->subMinutes(10),
        ]);

    $component = operationSupportRequestComponent($user, $run);

    expect(operationSupportRequestHeaderPrimaryNames($component))
        ->not->toContain('openSupportDiagnostics')
        ->not->toContain('requestSupport')
        ->and(operationSupportRequestHeaderMoreActionNames($component))
        ->toEqualCanonicalizing(['openSupportDiagnostics', 'requestSupport'])
        ->and(operationSupportRequestHeaderMoreAction($component, 'openSupportDiagnostics')?->isIconButton())
        ->toBeFalse();

    $component
        ->assertActionVisible('openSupportDiagnostics')
        ->assertActionEnabled('openSupportDiagnostics')
        ->assertActionVisible('requestSupport')
        ->assertActionEnabled('requestSupport')
        ->assertActionExists('requestSupport', fn (Action $action): bool => $action->getLabel() === 'Request support')
        ->mountAction('requestSupport')
        ->setActionData([
            'severity' => SupportRequest::SEVERITY_BLOCKING,
            'summary' => 'This failed operation needs support escalation.',
            'reproduction_notes' => 'Open the canonical run detail and submit the request from the grouped secondary action.',
        ])
        ->callMountedAction()
        ->assertHasNoActionErrors()
        ->assertNotified('Support request submitted');

    $supportRequest = SupportRequest::query()->sole();

    expect($supportRequest->internal_reference)->toMatch('/^SR-[0-9A-HJKMNP-TV-Z]{26}$/')
        ->and($supportRequest->workspace_id)->toBe((int) $tenant->workspace_id)
        ->and($supportRequest->managed_environment_id)->toBe((int) $tenant->getKey())
        ->and($supportRequest->initiated_by_user_id)->toBe((int) $user->getKey())
        ->and($supportRequest->primary_context_type)->toBe(SupportRequest::PRIMARY_CONTEXT_OPERATION_RUN)
        ->and($supportRequest->operation_run_id)->toBe((int) $run->getKey())
        ->and($supportRequest->attachment_mode)->toBe(SupportRequest::ATTACHMENT_MODE_DIAGNOSTIC_SNAPSHOT_ATTACHED)
        ->and($supportRequest->severity)->toBe(SupportRequest::SEVERITY_BLOCKING)
        ->and($supportRequest->summary)->toBe('This failed operation needs support escalation.')
        ->and(data_get($supportRequest->context_envelope, 'primary_context.type'))->toBe('operation_run')
        ->and(data_get($supportRequest->context_envelope, 'primary_context.operation_run_id'))->toBe((int) $run->getKey())
        ->and(data_get($supportRequest->context_envelope, 'diagnostic_snapshot'))->toBeArray();
});

it('keeps tenantless operation detail deny-as-not-found for workspace members without tenant entitlement', function (): void {
    $workspace = Workspace::factory()->create();
    $tenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
    ]);

    $user = User::factory()->create();

    WorkspaceMembership::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'owner',
    ]);
    createUserWithTenant(
        tenant: ManagedEnvironment::factory()->create(['workspace_id' => (int) $workspace->getKey()]),
        user: $user,
        role: 'owner',
    );

    $run = OperationRun::factory()->create([
        'managed_environment_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $workspace->getKey(),
        'type' => OperationRunType::BaselineCompare->value,
        'status' => OperationRunStatus::Completed->value,
        'outcome' => OperationRunOutcome::Succeeded->value,
        'completed_at' => now(),
    ]);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get(\App\Support\OperationRunLinks::tenantlessView($run))
        ->assertNotFound();
});
