<?php

declare(strict_types=1);

use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
use App\Filament\Resources\TenantReviewResource;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\Tenant;
use App\Models\User;
use App\Support\Governance\Controls\ComplianceEvidenceMappingV1;
use App\Support\TenantReviewStatus;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

it('lists only the latest published review per entitled tenant on the customer review workspace', function (): void {
    $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']);
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
        'name' => 'Beta Tenant',
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');

    $tenantDenied = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
        'name' => 'Denied Tenant',
    ]);
    $otherOwner = User::factory()->create();
    createUserWithTenant(tenant: $tenantDenied, user: $otherOwner, role: 'owner');

    $tenantASnapshot = seedTenantReviewEvidence($tenantA);
    $tenantBSnapshot = seedTenantReviewEvidence($tenantB);
    $tenantDeniedSnapshot = seedTenantReviewEvidence($tenantDenied);

    $olderPublishedReview = composeTenantReviewForTest($tenantA, $user, $tenantASnapshot);
    $olderPublishedReview->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'generated_at' => now()->subDays(3),
        'published_at' => now()->subDays(3),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $newerInternalReview = $olderPublishedReview->replicate();
    $newerInternalReview->forceFill([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(),
        'status' => TenantReviewStatus::Ready->value,
        'generated_at' => now()->subDay(),
        'published_at' => null,
        'published_by_user_id' => null,
    ])->save();

    $latestPublishedReview = $olderPublishedReview->replicate();
    $latestPublishedReview->forceFill([
        'tenant_id' => (int) $tenantA->getKey(),
        'workspace_id' => (int) $tenantA->workspace_id,
        'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(),
        'status' => TenantReviewStatus::Published->value,
        'generated_at' => now(),
        'published_at' => now(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $betaPublishedReview = composeTenantReviewForTest($tenantB, $user, $tenantBSnapshot);
    $betaPublishedReview->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'generated_at' => now()->subHours(2),
        'published_at' => now()->subHours(2),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $deniedPublishedReview = composeTenantReviewForTest($tenantDenied, $otherOwner, $tenantDeniedSnapshot);
    $deniedPublishedReview->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'generated_at' => now()->subHours(3),
        'published_at' => now()->subHours(3),
        'published_by_user_id' => (int) $otherOwner->getKey(),
    ])->save();

    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    Livewire::actingAs($user)
        ->test(CustomerReviewWorkspace::class)
        ->assertCanSeeTableRecords([$tenantA->fresh(), $tenantB->fresh()])
        ->assertCanNotSeeTableRecords([$tenantDenied->fresh()])
        ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $latestPublishedReview->fresh()], $tenantA), false)
        ->assertSee('Review the executive-ready governance package status for each entitled tenant and open the customer-safe detail when follow-up is needed.')
        ->assertSee('Each row is an index entry: open the review detail to inspect package status, the executive entrypoint, supporting evidence, current risks, and the next customer-safe action.')
        ->assertSee('This workspace summarizes current review evidence for service delivery. It does not replace a formal audit opinion, certification, or legal attestation.')
        ->assertSee('Governance package')
        ->assertSee('Status')
        ->assertSee('Evidence')
        ->assertSee('Next step')
        ->assertSee('Open')
        ->assertSee('Open review')
        ->assertDontSee('Assessment status')
        ->assertDontSee('Publishable')
        ->assertDontSee('No mapped controls')
        ->assertDontSee('Compliance evidence mapping v1')
        ->assertDontSee(ComplianceEvidenceMappingV1::VERSION_KEY)
        ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $betaPublishedReview->fresh()], $tenantB), false)
        ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $olderPublishedReview->fresh()], $tenantA), false)
        ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $newerInternalReview->fresh()], $tenantA), false)
        ->assertDontSee('Publish review')
        ->assertDontSee('Refresh review')
        ->assertDontSee('Create next review')
        ->assertDontSee('Regenerate')
        ->assertDontSee('Expire snapshot')
        ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $deniedPublishedReview->fresh()], $tenantDenied), false);
});

it('excludes entitled tenants without a published review from customer workspace rows', function (): void {
    $tenantPublished = Tenant::factory()->create(['name' => 'Published Tenant']);
    [$user, $tenantPublished] = createUserWithTenant(tenant: $tenantPublished, role: 'readonly');

    $tenantWithoutPublished = Tenant::factory()->create([
        'workspace_id' => (int) $tenantPublished->workspace_id,
        'name' => 'No Published Tenant',
    ]);
    createUserWithTenant(tenant: $tenantWithoutPublished, user: $user, role: 'readonly');

    $publishedSnapshot = seedTenantReviewEvidence($tenantPublished);
    $noPublishedSnapshot = seedTenantReviewEvidence($tenantWithoutPublished);

    $publishedReview = composeTenantReviewForTest($tenantPublished, $user, $publishedSnapshot);
    $publishedReview->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'published_at' => now()->subHour(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $internalOnlyReview = composeTenantReviewForTest($tenantWithoutPublished, $user, $noPublishedSnapshot);
    $internalOnlyReview->forceFill([
        'status' => TenantReviewStatus::Ready->value,
        'published_at' => null,
        'published_by_user_id' => null,
    ])->save();

    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantPublished->workspace_id);

    Livewire::actingAs($user)
        ->test(CustomerReviewWorkspace::class)
        ->assertCanSeeTableRecords([$tenantPublished->fresh()])
        ->assertCanNotSeeTableRecords([$tenantWithoutPublished->fresh()])
        ->assertDontSee('No published review')
        ->assertDontSee('No published review available yet')
        ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenantWithoutPublished), false)
        ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $publishedReview->fresh()], $tenantPublished), false);
});

it('uses a page-level empty state when no entitled tenant has a released review', function (): void {
    $tenant = Tenant::factory()->create(['name' => 'Internal Only Tenant']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
    $snapshot = seedTenantReviewEvidence($tenant);

    $internalOnlyReview = composeTenantReviewForTest($tenant, $user, $snapshot);
    $internalOnlyReview->forceFill([
        'status' => TenantReviewStatus::Ready->value,
        'published_at' => null,
        'published_by_user_id' => null,
    ])->save();

    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(CustomerReviewWorkspace::class)
        ->assertCanNotSeeTableRecords([$tenant->fresh()])
        ->assertSee('No released customer reviews match this view')
        ->assertSee('Publish a tenant review before it appears in the customer-safe workspace.')
        ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenant), false);
});

it('summarizes accepted-risk control interpretation and evidence proof availability in customer-safe workspace rows', function (): void {
    $tenant = Tenant::factory()->create(['name' => 'Governed Tenant']);
    [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
    $owner = User::factory()->create(['name' => 'Risk Owner']);
    $finding = Finding::factory()->create([
        'tenant_id' => (int) $tenant->getKey(),
        'workspace_id' => (int) $tenant->workspace_id,
        'status' => Finding::STATUS_RISK_ACCEPTED,
    ]);

    FindingException::query()->create([
        'workspace_id' => (int) $tenant->workspace_id,
        'tenant_id' => (int) $tenant->getKey(),
        'finding_id' => (int) $finding->getKey(),
        'status' => FindingException::STATUS_ACTIVE,
        'current_validity_state' => FindingException::VALIDITY_VALID,
        'requested_by_user_id' => (int) $user->getKey(),
        'request_reason' => 'Vendor patch window accepted by the customer.',
        'owner_user_id' => (int) $owner->getKey(),
        'approved_by_user_id' => (int) $owner->getKey(),
        'requested_at' => now()->subDays(2),
        'approved_at' => now()->subDay(),
        'effective_from' => now()->subDay(),
        'review_due_at' => now()->addDays(14),
    ]);

    $snapshot = seedTenantReviewEvidence($tenant, findingCount: 0, driftCount: 0);

    $review = composeTenantReviewForTest($tenant, $user, $snapshot);
    $review->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'published_at' => now(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();
    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);

    Livewire::actingAs($user)
        ->test(CustomerReviewWorkspace::class)
        ->assertCanSeeTableRecords([$tenant->fresh()])
        ->assertSee('Review required')
        ->assertSee('Open review')
        ->assertDontSee('Ready for release')
        ->assertDontSee('1 evidence signal(s) reference this control.')
        ->assertDontSee('1 accepted-risk finding(s) qualify this view.')
        ->assertDontSee('Review the accepted-risk owner and next review date before customer delivery.')
        ->assertDontSee('Accepted risk influences this view');
});

it('defaults the customer review workspace to the remembered tenant when tenant context is available', function (): void {
    $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']);
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
        'name' => 'Beta Tenant',
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');

    $snapshotA = seedTenantReviewEvidence($tenantA);
    $snapshotB = seedTenantReviewEvidence($tenantB);

    $reviewA = composeTenantReviewForTest($tenantA, $user, $snapshotA);
    $reviewA->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'published_at' => now()->subDay(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $reviewB = composeTenantReviewForTest($tenantB, $user, $snapshotB);
    $reviewB->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'published_at' => now(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
    session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
        (string) $tenantA->workspace_id => (int) $tenantB->getKey(),
    ]);

    Livewire::actingAs($user)
        ->test(CustomerReviewWorkspace::class)
        ->assertSet('tableFilters.tenant_id.value', (string) $tenantB->getKey())
        ->filterTable('tenant_id', (string) $tenantB->getKey())
        ->assertCanSeeTableRecords([$tenantB->fresh()])
        ->assertCanNotSeeTableRecords([$tenantA->fresh()]);
});

it('prefilters the customer review workspace from an explicit tenant query parameter and accepts external tenant identifiers', function (): void {
    $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']);
    [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');

    $tenantB = Tenant::factory()->create([
        'workspace_id' => (int) $tenantA->workspace_id,
        'name' => 'Beta Tenant',
    ]);
    createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');

    $snapshotA = seedTenantReviewEvidence($tenantA);
    $snapshotB = seedTenantReviewEvidence($tenantB);

    $reviewA = composeTenantReviewForTest($tenantA, $user, $snapshotA);
    $reviewA->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'published_at' => now(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $reviewB = composeTenantReviewForTest($tenantB, $user, $snapshotB);
    $reviewB->forceFill([
        'status' => TenantReviewStatus::Published->value,
        'published_at' => now()->subDay(),
        'published_by_user_id' => (int) $user->getKey(),
    ])->save();

    $this->actingAs($user);
    setAdminPanelContext();
    session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);

    Livewire::withQueryParams(['tenant' => (string) $tenantA->external_id])
        ->test(CustomerReviewWorkspace::class)
        ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey())
        ->filterTable('tenant_id', (string) $tenantA->getKey())
        ->assertCanSeeTableRecords([$tenantA->fresh()])
        ->assertCanNotSeeTableRecords([$tenantB->fresh()]);
});
