<?php

namespace Tests\Feature\BranchIsolation;

use App\Models\Branch;
use App\Models\Business;
use App\Models\CashReconciliation;
use App\Models\FinancialAccount;
use App\Models\FinancialTransfer;
use App\Models\User;
use App\Services\FinancialAccountingService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class IndirectFinanceScopeTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_cash_reconciliations_and_transfers_are_scoped_to_accessible_account_branches(): void
    {
        $business = Business::firstOrFail();
        $admin = User::where('email', 'admin@microfinance.local')->firstOrFail();
        $branchA = Branch::create(['business_id' => $business->id, 'name' => 'Scope Finance A', 'status' => 'active']);
        $branchB = Branch::create(['business_id' => $business->id, 'name' => 'Scope Finance B', 'status' => 'active']);

        $accountA1 = $this->account($admin, $branchA, 'Scope A Cash');
        $accountA2 = $this->account($admin, $branchA, 'Scope A Bank');
        $accountB1 = $this->account($admin, $branchB, 'Scope B Cash');
        $accountB2 = $this->account($admin, $branchB, 'Scope B Bank');

        $reconciliationA = $this->reconciliation($admin, $business, $branchA, $accountA1, 'REC-SCOPE-A');
        $reconciliationB = $this->reconciliation($admin, $business, $branchB, $accountB1, 'REC-SCOPE-B');

        $transferAA = FinancialTransfer::create([
            'transfer_number' => 'TRF-SCOPE-AA',
            'source_account_id' => $accountA1->id,
            'destination_account_id' => $accountA2->id,
            'amount' => '10.00',
            'transfer_date' => '2026-08-13',
            'created_by' => $admin->id,
        ]);
        $transferAB = FinancialTransfer::create([
            'transfer_number' => 'TRF-SCOPE-AB',
            'source_account_id' => $accountA1->id,
            'destination_account_id' => $accountB1->id,
            'amount' => '10.00',
            'transfer_date' => '2026-08-13',
            'created_by' => $admin->id,
        ]);
        $transferBB = FinancialTransfer::create([
            'transfer_number' => 'TRF-SCOPE-BB',
            'source_account_id' => $accountB1->id,
            'destination_account_id' => $accountB2->id,
            'amount' => '10.00',
            'transfer_date' => '2026-08-13',
            'created_by' => $admin->id,
        ]);

        $branchUser = User::factory()->create([
            'name' => 'Scoped Finance User',
            'username' => 'scoped_finance_user',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $branchUser->branches()->attach($branchA->id, ['is_primary' => true]);

        $this->actingAs($branchUser);
        $this->assertSame([$reconciliationA->id], CashReconciliation::pluck('id')->all());
        $this->assertSame([$transferAA->id], FinancialTransfer::pluck('id')->all());
        $this->assertFalse(FinancialTransfer::whereKey($transferAB->id)->exists());
        $this->assertFalse(FinancialTransfer::whereKey($transferBB->id)->exists());

        $branchUser->branches()->attach($branchB->id, ['is_primary' => false]);

        $this->assertEqualsCanonicalizing(
            [$reconciliationA->id, $reconciliationB->id],
            CashReconciliation::pluck('id')->all()
        );
        $this->assertEqualsCanonicalizing(
            [$transferAA->id, $transferAB->id, $transferBB->id],
            FinancialTransfer::pluck('id')->all()
        );

        $this->actingAs($admin);
        $this->assertSame(2, CashReconciliation::count());
        $this->assertSame(3, FinancialTransfer::count());
    }

    private function account(User $admin, Branch $branch, string $name): FinancialAccount
    {
        return app(FinancialAccountingService::class)->createAccount([
            'branch_id' => $branch->id,
            'name' => $name,
            'account_type' => str_contains($name, 'Cash') ? 'cash' : 'bank',
            'opening_balance' => '100.00',
            'status' => 'active',
        ], $admin);
    }

    private function reconciliation(
        User $admin,
        Business $business,
        Branch $branch,
        FinancialAccount $account,
        string $number
    ): CashReconciliation {
        return CashReconciliation::create([
            'reconciliation_number' => $number,
            'business_id' => $business->id,
            'branch_id' => $branch->id,
            'financial_account_id' => $account->id,
            'reconciliation_date' => '2026-08-13',
            'physical_cash' => '100.00',
            'expected_cash' => '100.00',
            'variance' => '0.00',
            'reconciled_by' => $admin->id,
            'reconciled_at' => now(),
        ]);
    }
}
