<?php

namespace Tests\Feature\BranchIsolation;

use App\Models\Branch;
use App\Models\Business;
use App\Models\Collateral;
use App\Models\CollateralCategory;
use App\Models\Customer;
use App\Models\FixedAsset;
use App\Models\Role;
use App\Models\User;
use App\Services\BranchAccessService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class StaffAssignmentIntegrityTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed(DatabaseSeeder::class);
    }

    public function test_multi_branch_manager_cannot_attach_staff_from_another_branch_to_branch_local_records(): void
    {
        $business = Business::firstOrFail();
        $branchA = Branch::create(['business_id' => $business->id, 'name' => 'Staff Integrity A', 'status' => 'active']);
        $branchB = Branch::create(['business_id' => $business->id, 'name' => 'Staff Integrity B', 'status' => 'active']);

        $actor = User::factory()->create([
            'name' => 'Multi Branch Manager',
            'username' => 'staff_integrity_manager',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $actor->roles()->attach(Role::where('name', 'branch-manager')->firstOrFail());
        $actor->branches()->attach($branchA->id, ['is_primary' => true]);
        $actor->branches()->attach($branchB->id, ['is_primary' => false]);

        $primaryOnlyA = User::factory()->create([
            'name' => 'Primary Only Receiver A',
            'username' => 'primary_only_receiver_a',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $branchBStaff = User::factory()->create([
            'name' => 'Branch B Receiver',
            'username' => 'branch_b_receiver',
            'status' => 'active',
            'primary_branch_id' => $branchB->id,
        ]);
        $branchBStaff->branches()->attach($branchB->id, ['is_primary' => true]);

        $customer = Customer::create([
            'branch_id' => $branchA->id,
            'customer_number' => 'CUS-STAFF-INTEGRITY-A',
            'identity_mode' => 'without_nin',
            'first_name' => 'Asha',
            'last_name' => 'Musa',
            'phone' => '0755112200',
            'status' => 'active',
        ]);
        $category = CollateralCategory::where('business_id', $business->id)->where('name', 'Television')->firstOrFail();

        $collateralPayload = [
            'customer_id' => $customer->id,
            'branch_id' => $branchA->id,
            'category_id' => $category->id,
            'item' => 'Integrity Television',
            'accepted_value' => '500000.00',
            'received_at' => '2026-08-13',
            'status' => 'pending_inspection',
        ];

        $this->actingAs($actor)
            ->from(route('collateral.create'))
            ->post(route('collateral.store'), $collateralPayload + ['received_by' => $branchBStaff->id])
            ->assertRedirect(route('collateral.create'))
            ->assertSessionHasErrors('received_by');
        $this->assertSame(0, Collateral::count());

        $this->actingAs($actor)
            ->post(route('collateral.store'), $collateralPayload + ['received_by' => $primaryOnlyA->id])
            ->assertRedirect();
        $this->assertSame($primaryOnlyA->id, Collateral::firstOrFail()->received_by);

        $assetPayload = [
            'branch_id' => $branchA->id,
            'name' => 'Integrity Laptop',
            'category' => 'Computer Equipment',
            'acquisition_source' => 'opening',
            'acquisition_date' => '2026-08-13',
            'acquisition_cost' => '1000.00',
            'residual_value' => '0.00',
            'depreciation_method' => 'none',
            'status' => 'active',
        ];

        $this->actingAs($actor)
            ->from(route('fixed-assets.create'))
            ->post(route('fixed-assets.store'), $assetPayload + ['custodian_user_id' => $branchBStaff->id])
            ->assertRedirect(route('fixed-assets.create'))
            ->assertSessionHasErrors('custodian_user_id');
        $this->assertSame(0, FixedAsset::count());

        $this->actingAs($actor)
            ->post(route('fixed-assets.store'), $assetPayload + ['custodian_user_id' => $primaryOnlyA->id])
            ->assertRedirect();
        $this->assertSame($primaryOnlyA->id, FixedAsset::firstOrFail()->custodian_user_id);
    }

    public function test_system_wide_access_does_not_count_as_branch_staff_assignment(): void
    {
        $business = Business::firstOrFail();
        $branch = Branch::create(['business_id' => $business->id, 'name' => 'Assignment Semantics', 'status' => 'active']);
        $super = User::factory()->create([
            'name' => 'Unassigned System Administrator',
            'username' => 'unassigned_system_admin',
            'status' => 'active',
            'primary_branch_id' => null,
        ]);
        $super->roles()->attach(Role::where('name', 'super-administrator')->firstOrFail());

        $access = app(BranchAccessService::class);

        $this->assertTrue($access->canAccessBranch($super, $branch->id));
        $this->assertFalse($access->isAssignedToBranch($super, $branch->id));
        $this->assertSame([], $access->assignedBranchIds($super));
    }
}
