<?php

declare(strict_types=1);

use App\Filament\Resources\BaselineProfileResource;
use App\Models\BaselineProfile;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;

uses(RefreshDatabase::class);

describe('BaselineProfile RBAC — 404 vs 403 semantics', function () {
    it('denies non-members accessing the list page', function (): void {
        $user = User::factory()->create();
        $workspace = Workspace::factory()->create();

        session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

        $response = $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl(panel: 'admin'));

        expect($response->status())->toBeIn([403, 404, 302], 'Non-members should not get HTTP 200');
    });

    it('returns 404 for members accessing a profile from another workspace', function (): void {
        [$user, $tenant] = createUserWithTenant(role: 'owner');

        $otherWorkspace = Workspace::factory()->create();
        $profile = BaselineProfile::factory()->create([
            'workspace_id' => (int) $otherWorkspace->getKey(),
        ]);

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl('view', ['record' => $profile], panel: 'admin'))
            ->assertNotFound();
    });

    it('returns 200 for readonly members accessing list page', function (): void {
        [$user] = createUserWithTenant(role: 'readonly');

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl(panel: 'admin'))
            ->assertOk();
    });

    it('returns 403 for members with mocked missing capability on list page', function (): void {
        $workspace = Workspace::factory()->create();
        $user = User::factory()->create();

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

        $resolver = \Mockery::mock(WorkspaceCapabilityResolver::class);
        $resolver->shouldReceive('isMember')->andReturnTrue();
        $resolver->shouldReceive('can')->andReturnFalse();
        app()->instance(WorkspaceCapabilityResolver::class, $resolver);

        session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl(panel: 'admin'))
            ->assertForbidden();
    });

    it('returns 403 for readonly members accessing create page', function (): void {
        [$user] = createUserWithTenant(role: 'readonly');

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl('create', panel: 'admin'))
            ->assertForbidden();
    });

    it('returns 200 for owner members accessing create page', function (): void {
        [$user] = createUserWithTenant(role: 'owner');

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl('create', panel: 'admin'))
            ->assertOk();
    });

    it('returns 404 for members accessing profile from another workspace', function (): void {
        [$user, $tenant] = createUserWithTenant(role: 'owner');

        $otherWorkspace = Workspace::factory()->create();
        $profile = BaselineProfile::factory()->create([
            'workspace_id' => (int) $otherWorkspace->getKey(),
        ]);

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl('view', ['record' => $profile], panel: 'admin'))
            ->assertNotFound();
    });

    it('returns 403 for readonly members accessing edit page', function (): void {
        [$user, $tenant] = createUserWithTenant(role: 'readonly');

        $workspace = Workspace::query()->whereKey($tenant->workspace_id)->first();
        $profile = BaselineProfile::factory()->create([
            'workspace_id' => (int) $workspace->getKey(),
        ]);

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl('edit', ['record' => $profile], panel: 'admin'))
            ->assertForbidden();
    });

    it('returns 200 for owner members accessing edit page', function (): void {
        [$user, $tenant] = createUserWithTenant(role: 'owner');

        $workspace = Workspace::query()->whereKey($tenant->workspace_id)->first();
        $profile = BaselineProfile::factory()->create([
            'workspace_id' => (int) $workspace->getKey(),
        ]);

        $this->actingAs($user)
            ->get(BaselineProfileResource::getUrl('edit', ['record' => $profile], panel: 'admin'))
            ->assertOk();
    });

    it('keeps edit-page authorization stable for legacy-scope profiles', function (): void {
        [$owner, $tenant] = createUserWithTenant(role: 'owner');
        [$readonly] = createUserWithTenant(tenant: $tenant, role: 'readonly');

        $profile = BaselineProfile::factory()->create([
            'workspace_id' => (int) $tenant->workspace_id,
        ]);

        DB::table('baseline_profiles')
            ->where('id', (int) $profile->getKey())
            ->update([
                'scope_jsonb' => json_encode([
                    'policy_types' => ['deviceConfiguration'],
                    'foundation_types' => [],
                ], JSON_THROW_ON_ERROR),
                'updated_at' => now(),
            ]);

        $this->actingAs($owner)
            ->get(BaselineProfileResource::getUrl('edit', ['record' => $profile], panel: 'admin'))
            ->assertOk();

        $this->actingAs($readonly)
            ->get(BaselineProfileResource::getUrl('edit', ['record' => $profile], panel: 'admin'))
            ->assertForbidden();
    });
});

describe('BaselineProfile static authorization methods', function () {
    it('canViewAny returns false for non-members', function (): void {
        $user = User::factory()->create();
        $workspace = Workspace::factory()->create();

        $this->actingAs($user);
        session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());

        expect(BaselineProfileResource::canViewAny())->toBeFalse();
    });

    it('canViewAny returns true for members', function (): void {
        [$user] = createUserWithTenant(role: 'readonly');

        $this->actingAs($user);

        expect(BaselineProfileResource::canViewAny())->toBeTrue();
    });

    it('canCreate returns true for managers and false for readonly', function (): void {
        [$owner] = createUserWithTenant(role: 'owner');
        $this->actingAs($owner);
        expect(BaselineProfileResource::canCreate())->toBeTrue();

        [$readonly] = createUserWithTenant(role: 'readonly');
        $this->actingAs($readonly);
        expect(BaselineProfileResource::canCreate())->toBeFalse();
    });
});
