<?php

use App\Enums\WorkspaceUserRole;
use App\Models\Client;
use App\Models\Declaration;
use App\Models\User;
use App\Models\Workspace;
use Inertia\Testing\AssertableInertia as Assert;

function setupDeclarationTestUser(string $role, array $permissions = []): array
{
    $user = User::factory()->create();
    $workspace = Workspace::factory()->create();
    $workspace->users()->attach($user->id, [
        'role' => $role,
        'permissions' => $permissions,
    ]);
    session(['current_workspace_id' => $workspace->id]);

    return [$user, $workspace];
}

// AC #2: Worker sees only assigned declarations in index
test('worker sees only assigned declarations in index', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);

    $assignedDeclaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
    ]);

    $unassignedDeclaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => null,
    ]);

    $otherUser = User::factory()->create();
    $otherAssignedDeclaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $otherUser->id,
    ]);

    $response = $this->actingAs($worker)->get(route('declarations.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('declarations/Index')
        ->has('declarations.data', 1)
        ->where('declarations.data.0.id', $assignedDeclaration->id)
    );
});

// AC #3: Owner sees all declarations
test('owner sees all declarations in index', function () {
    [$owner, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Owner);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);

    Declaration::factory()->count(5)->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    $response = $this->actingAs($owner)->get(route('declarations.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('declarations/Index')
        ->has('declarations.data', 5)
    );
});

// AC #3: Manager sees all declarations
test('manager sees all declarations in index', function () {
    [$manager, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Manager);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);

    Declaration::factory()->count(3)->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    $response = $this->actingAs($manager)->get(route('declarations.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('declarations/Index')
        ->has('declarations.data', 3)
    );
});

// AC #4: Worker gets 404 accessing unassigned declaration via direct URL
test('worker gets 404 accessing unassigned declaration via direct URL', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);

    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => null,
    ]);

    $response = $this->actingAs($worker)->get(route('declarations.show', $declaration));

    $response->assertNotFound();
});

// Worker can access assigned declaration show
test('worker can access assigned declaration show', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);

    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
    ]);

    $response = $this->actingAs($worker)->get(route('declarations.show', $declaration));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->component('declarations/Show')
    );
});

// AC #6: Worker gets 404 on create
test('worker gets 404 on declaration create', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $response = $this->actingAs($worker)->get(route('declarations.create'));

    $response->assertNotFound();
});

// Worker gets 404 on store
test('worker gets 404 on declaration store', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);

    $response = $this->actingAs($worker)->post(route('declarations.store'), [
        'title' => 'Test',
        'type' => 'vat_monthly',
        'client_id' => $client->id,
        'period_year' => 2026,
        'period_month' => 1,
    ]);

    $response->assertNotFound();
});

// Worker gets 404 on edit
test('worker gets 404 on declaration edit', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    $response = $this->actingAs($worker)->get(route('declarations.edit', $declaration));

    $response->assertNotFound();
});

// Worker gets 404 on update
test('worker gets 404 on declaration update', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    $response = $this->actingAs($worker)->put(route('declarations.update', $declaration), [
        'title' => 'Updated',
        'type' => 'vat_monthly',
        'client_id' => $client->id,
        'period_year' => 2026,
        'period_month' => 1,
    ]);

    $response->assertNotFound();
});

// Worker gets 404 on destroy
test('worker gets 404 on declaration destroy', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    $response = $this->actingAs($worker)->delete(route('declarations.destroy', $declaration));

    $response->assertNotFound();
});

// Manager can access all CRUD operations
test('manager can access all declaration CRUD operations', function () {
    [$manager, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Manager);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    // Index
    $this->actingAs($manager)->get(route('declarations.index'))->assertOk();

    // Show
    $this->actingAs($manager)->get(route('declarations.show', $declaration))->assertOk();

    // Create page
    $this->actingAs($manager)->get(route('declarations.create'))->assertOk();

    // Edit page
    $this->actingAs($manager)->get(route('declarations.edit', $declaration))->assertOk();
});

// Owner can access all CRUD operations
test('owner can access all declaration CRUD operations', function () {
    [$owner, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Owner);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    // Index
    $this->actingAs($owner)->get(route('declarations.index'))->assertOk();

    // Show
    $this->actingAs($owner)->get(route('declarations.show', $declaration))->assertOk();

    // Create page
    $this->actingAs($owner)->get(route('declarations.create'))->assertOk();

    // Edit page
    $this->actingAs($owner)->get(route('declarations.edit', $declaration))->assertOk();
});

// AC #10: canCreate/canEdit/canDelete props false for Workers
test('worker gets canCreate canEdit canDelete as false in declarations index', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $response = $this->actingAs($worker)->get(route('declarations.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('canCreate', false)
        ->where('canEdit', false)
        ->where('canDelete', false)
    );
});

// AC #10: canCreate/canEdit/canDelete props true for Owners
test('owner gets canCreate canEdit canDelete as true in declarations index', function () {
    [$owner, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Owner);

    $response = $this->actingAs($owner)->get(route('declarations.index'));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('canCreate', true)
        ->where('canEdit', true)
        ->where('canDelete', true)
    );
});

// AC #9: auth.workspaceRole is shared correctly
test('auth.workspaceRole is shared correctly for each role', function () {
    // Test Owner
    [$owner, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Owner);

    $response = $this->actingAs($owner)->get(route('declarations.index'));
    $response->assertInertia(fn (Assert $page) => $page
        ->where('auth.workspaceRole', 'owner')
    );

    // Test Manager
    [$manager, $workspace2] = setupDeclarationTestUser(WorkspaceUserRole::Manager);

    $response = $this->actingAs($manager)->get(route('declarations.index'));
    $response->assertInertia(fn (Assert $page) => $page
        ->where('auth.workspaceRole', 'manager')
    );

    // Test Worker
    [$worker, $workspace3] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $response = $this->actingAs($worker)->get(route('declarations.index'));
    $response->assertInertia(fn (Assert $page) => $page
        ->where('auth.workspaceRole', 'worker')
    );
});

// AC #11: Cross-workspace isolation
test('worker in workspace A cannot see declarations in workspace B', function () {
    [$worker, $workspaceA] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $workspaceB = Workspace::factory()->create();
    $clientB = Client::factory()->create(['workspace_id' => $workspaceB->id]);

    $declarationInB = Declaration::factory()->create([
        'workspace_id' => $workspaceB->id,
        'client_id' => $clientB->id,
        'assigned_to' => $worker->id,
    ]);

    // Worker should not see workspace B declarations in their index
    $response = $this->actingAs($worker)->get(route('declarations.index'));
    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->has('declarations.data', 0)
    );

    // Worker should get 404 trying to access workspace B declaration directly
    $response = $this->actingAs($worker)->get(route('declarations.show', $declarationInB));
    $response->assertNotFound();
});

// canMention is false for workers in declaration show
test('worker gets canMention as false in declaration show', function () {
    [$worker, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Worker);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
        'assigned_to' => $worker->id,
    ]);

    $response = $this->actingAs($worker)->get(route('declarations.show', $declaration));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('canMention', false)
        ->where('canEdit', false)
        ->where('canDelete', false)
    );
});

// canMention is true for owners/managers in declaration show
test('owner gets canMention as true in declaration show', function () {
    [$owner, $workspace] = setupDeclarationTestUser(WorkspaceUserRole::Owner);

    $client = Client::factory()->create(['workspace_id' => $workspace->id]);
    $declaration = Declaration::factory()->create([
        'workspace_id' => $workspace->id,
        'client_id' => $client->id,
    ]);

    $response = $this->actingAs($owner)->get(route('declarations.show', $declaration));

    $response->assertOk();
    $response->assertInertia(fn (Assert $page) => $page
        ->where('canMention', true)
        ->where('canEdit', true)
        ->where('canDelete', true)
    );
});
