<?php

declare(strict_types=1);

use App\Filament\Pages\EnvironmentDashboard;
use App\Models\SupportRequest;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentMembership;
use App\Models\User;
use App\Models\WorkspaceMembership;
use App\Services\Auth\CapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Actions\Action;
use Livewire\Livewire;

use function Pest\Laravel\mock;

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

function tenantSupportRequestComponent(User $user, ManagedEnvironment $tenant): \Livewire\Features\SupportTesting\Testable
{
    test()->actingAs($user);
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
    setAdminEnvironmentContext($tenant);

    return Livewire::actingAs($user)->test(EnvironmentDashboard::class);
}

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

    tenantSupportRequestComponent($user, $tenant)
        ->assertActionVisible('requestSupport')
        ->assertActionEnabled('requestSupport')
        ->assertActionExists('requestSupport', fn (Action $action): bool => $action->getLabel() === 'Request support')
        ->mountAction('requestSupport')
        ->setActionData([
            'severity' => SupportRequest::SEVERITY_HIGH,
            'summary' => 'Policy sync failed after the latest tenant refresh.',
            'reproduction_notes' => 'Open the tenant dashboard after a failed sync and request support from the header action.',
            'contact_name' => 'Ops On Call',
            'contact_email' => 'ops@example.test',
        ])
        ->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_TENANT)
        ->and($supportRequest->operation_run_id)->toBeNull()
        ->and($supportRequest->attachment_mode)->toBe(SupportRequest::ATTACHMENT_MODE_DIAGNOSTIC_SNAPSHOT_ATTACHED)
        ->and($supportRequest->severity)->toBe(SupportRequest::SEVERITY_HIGH)
        ->and($supportRequest->summary)->toBe('Policy sync failed after the latest tenant refresh.')
        ->and($supportRequest->reproduction_notes)->toContain('failed sync')
        ->and($supportRequest->contact_name)->toBe('Ops On Call')
        ->and($supportRequest->contact_email)->toBe('ops@example.test')
        ->and(data_get($supportRequest->context_envelope, 'primary_context.type'))->toBe('tenant')
        ->and(data_get($supportRequest->context_envelope, 'primary_context.managed_environment_id'))->toBe((int) $tenant->getKey())
        ->and(data_get($supportRequest->context_envelope, 'diagnostic_snapshot'))->toBeArray();
});

it('stores canonical context only when the creator cannot view support diagnostics', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');

    mock(CapabilityResolver::class, function ($mock) use ($tenant): void {
        $mock->shouldReceive('primeMemberships')->andReturnNull();
        $mock->shouldReceive('isMember')
            ->andReturnUsing(static fn ($user, ManagedEnvironment $resolvedTenant): bool => (int) $resolvedTenant->getKey() === (int) $tenant->getKey());

        $mock->shouldReceive('can')
            ->andReturnUsing(static function ($user, ManagedEnvironment $resolvedTenant, string $capability) use ($tenant): bool {
                expect((int) $resolvedTenant->getKey())->toBe((int) $tenant->getKey());

                return match ($capability) {
                    Capabilities::SUPPORT_REQUESTS_CREATE => true,
                    Capabilities::SUPPORT_DIAGNOSTICS_VIEW => false,
                    default => true,
                };
            });
    });

    tenantSupportRequestComponent($user, $tenant)
        ->assertActionVisible('requestSupport')
        ->assertActionEnabled('requestSupport')
        ->mountAction('requestSupport')
        ->setActionData([
            'summary' => 'Need help reviewing the latest tenant support context.',
        ])
        ->callMountedAction()
        ->assertHasNoActionErrors()
        ->assertNotified('Support request submitted');

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

    expect($supportRequest->severity)->toBe(SupportRequest::SEVERITY_NORMAL)
        ->and($supportRequest->contact_name)->toBe($user->name)
        ->and($supportRequest->contact_email)->toBe($user->email)
        ->and($supportRequest->attachment_mode)->toBe(SupportRequest::ATTACHMENT_MODE_CANONICAL_CONTEXT_ONLY)
        ->and(data_get($supportRequest->context_envelope, 'diagnostic_snapshot'))->toBeNull()
        ->and(data_get($supportRequest->context_envelope, 'omissions.0.reason'))->toBe('omitted_without_support_diagnostics_view');
});

it('keeps tenant dashboard support requests deny-as-not-found for workspace members outside their explicit environment scope', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    $allowedTenant = ManagedEnvironment::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
    ]);
    $user = User::factory()->create();

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

    ManagedEnvironmentMembership::query()->create([
        'managed_environment_id' => (int) $allowedTenant->getKey(),
        'user_id' => (int) $user->getKey(),
        'role' => 'operator',
        'source' => 'manual',
        'source_ref' => null,
        'created_by_user_id' => null,
    ]);

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get(EnvironmentDashboard::getUrl(panel: 'admin', tenant: $tenant))
        ->assertNotFound();
});

it('returns forbidden for entitled tenant members without support request capability', function (): void {
    $tenant = ManagedEnvironment::factory()->create();
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');

    tenantSupportRequestComponent($user, $tenant)
        ->assertActionVisible('requestSupport')
        ->assertActionDisabled('requestSupport')
        ->call('authorizeTenantSupportRequest')
        ->assertForbidden();

    expect(SupportRequest::query()->count())->toBe(0);
});
