<?php

declare(strict_types=1);

use App\Filament\Resources\ProviderConnectionResource;
use App\Filament\Resources\TenantResource;
use App\Models\AuditLog;
use App\Models\ProviderConnection;
use App\Models\Tenant;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\TenantMembershipManager;
use App\Support\Audit\AuditActionId;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Http::preventStrayRequests();
});

it('allows workspace members to open the workspace-managed tenants index', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get('/admin/tenants')
        ->assertOk();
});

it('redirects non-members on the workspace-managed tenants index', function (): void {
    $tenant = Tenant::factory()->create();
    $user = User::factory()->create();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get('/admin/tenants')
        ->assertRedirect();
});

it('allows workspace members to open the workspace-managed tenant view route', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}")
        ->assertOk();
});

it('exposes a provider connections link from the workspace-managed tenant view page', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}")
        ->assertOk()
        ->assertSee('/admin/provider-connections?tenant_id='.$tenant->external_id, false);
});

it('redirects non-members on the workspace-managed tenant view route', function (): void {
    $tenant = Tenant::factory()->create();
    $user = User::factory()->create();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}")
        ->assertRedirect();
});

it('exposes memberships management under workspace scope', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}/memberships")
        ->assertOk();
});

it('requires tenant entitlement for the contracted tenant operational routes', function (): void {
    $workspace = Workspace::factory()->create();

    $tenant = Tenant::factory()->create([
        'workspace_id' => (int) $workspace->getKey(),
        'external_id' => '11111111-1111-1111-1111-111111111111',
        'tenant_id' => '11111111-1111-1111-1111-111111111111',
    ]);

    [$entitledUser] = createUserWithTenant($tenant, role: 'readonly');

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

    $this->actingAs($entitledUser)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get("/admin/t/{$tenant->external_id}")
        ->assertOk();

    $this->actingAs($entitledUser)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get("/admin/t/{$tenant->external_id}/diagnostics")
        ->assertOk();

    $this->actingAs($nonEntitledUser)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get("/admin/t/{$tenant->external_id}")
        ->assertNotFound();

    $this->actingAs($nonEntitledUser)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
        ->get("/admin/t/{$tenant->external_id}/diagnostics")
        ->assertNotFound();
});

it('keeps tenant panel route shape canonical and rejects duplicated /t prefixes', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/t/{$tenant->external_id}/diagnostics")
        ->assertOk();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/t/t/{$tenant->external_id}/diagnostics")
        ->assertNotFound();
});

it('removes tenant-scoped management routes', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/t/{$tenant->external_id}/provider-connections")
        ->assertNotFound();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/t/{$tenant->external_id}/required-permissions")
        ->assertNotFound();

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/t/{$tenant->external_id}/memberships")
        ->assertNotFound();
});

it('serves provider connection management under workspace-managed tenant routes only', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $connection = ProviderConnection::factory()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'tenant_id' => (int) $tenant->getKey(),
    ]);

    $this->followingRedirects()
        ->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}/provider-connections")
        ->assertOk();

    $this->followingRedirects()
        ->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}/provider-connections/{$connection->getKey()}/edit")
        ->assertOk();
});

it('returns 403 for workspace members missing mutation capability on provider connections', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'readonly', workspaceRole: 'readonly');

    $this->followingRedirects()
        ->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}/provider-connections")
        ->assertOk();

    $this->followingRedirects()
        ->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/tenants/{$tenant->external_id}/provider-connections/create")
        ->assertForbidden();
});

it('writes canonical membership audit entries for membership mutations', function (): void {
    [$owner, $tenant] = createUserWithTenant(role: 'owner');
    $member = User::factory()->create();

    /** @var TenantMembershipManager $manager */
    $manager = app(TenantMembershipManager::class);

    $membership = $manager->addMember(
        tenant: $tenant,
        actor: $owner,
        member: $member,
        role: 'readonly',
        source: 'manual',
    );

    $manager->changeRole(
        tenant: $tenant,
        actor: $owner,
        membership: $membership,
        newRole: 'operator',
    );

    $manager->removeMember(
        tenant: $tenant,
        actor: $owner,
        membership: $membership,
    );

    $actions = AuditLog::query()
        ->where('tenant_id', (int) $tenant->getKey())
        ->whereIn('action', [
            AuditActionId::TenantMembershipAdd->value,
            AuditActionId::TenantMembershipRoleChange->value,
            AuditActionId::TenantMembershipRemove->value,
        ])
        ->pluck('action')
        ->all();

    expect($actions)->toContain(AuditActionId::TenantMembershipAdd->value);
    expect($actions)->toContain(AuditActionId::TenantMembershipRoleChange->value);
    expect($actions)->toContain(AuditActionId::TenantMembershipRemove->value);
});

it('keeps workspace navigation entries after panel split', function (): void {
    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get('/admin/tenants')
        ->assertOk()
        ->assertSee('Tenants')
        ->assertSee('Operations')
        ->assertSee('Alerts')
        ->assertSee('Audit Log');
});

it('does not expose tenant-management resources in tenant panel registration or navigation URLs', function (): void {
    $tenantPanelResources = Filament::getPanel('tenant')->getResources();

    expect($tenantPanelResources)->not->toContain(TenantResource::class);
    expect($tenantPanelResources)->not->toContain(ProviderConnectionResource::class);

    [$user, $tenant] = createUserWithTenant(role: 'owner');

    $this->actingAs($user)
        ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
        ->get("/admin/t/{$tenant->external_id}")
        ->assertOk()
        ->assertDontSee("/admin/t/{$tenant->external_id}/provider-connections", false)
        ->assertDontSee("/admin/t/{$tenant->external_id}/tenants", false);
});

it('keeps global search scoped to workspace-managed tenant resources only', function (): void {
    [$workspaceUser, $tenant] = createUserWithTenant(role: 'owner');

    Filament::setCurrentPanel('admin');
    Filament::setTenant(null, true);

    $this->actingAs($workspaceUser);

    $results = TenantResource::getGlobalSearchResults((string) $tenant->name);

    expect($results->count())->toBeGreaterThan(0);

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

    Filament::setCurrentPanel('admin');
    Filament::setTenant(null, true);

    $this->actingAs($nonMember);

    $nonMemberResults = TenantResource::getGlobalSearchResults((string) $tenant->name);

    expect($nonMemberResults)->toHaveCount(0);
});
