<?php

namespace Tests\Feature\BranchIsolation;

use App\Models\Branch;
use App\Models\Business;
use App\Models\Customer;
use App\Models\FinancialAccount;
use App\Models\FixedAsset;
use App\Models\Loan;
use App\Models\LoanProduct;
use App\Models\Permission;
use App\Models\Role;
use App\Models\User;
use App\Services\GlobalSearchService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class Phase5ReportScopeTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_primary_only_user_keeps_dashboard_and_search_access_to_primary_branch(): void
    {
        $business = Business::firstOrFail();
        $branch = Branch::create([
            'business_id' => $business->id,
            'name' => 'Phase 5 Primary Only',
            'status' => 'active',
        ]);

        $role = Role::create([
            'name' => 'phase5-primary-only',
            'display_name' => 'Phase 5 Primary Only',
        ]);
        $role->permissions()->attach(
            Permission::whereIn('name', ['dashboard.view', 'search.use', 'reports.view', 'customers.view'])->pluck('id')
        );

        $user = User::factory()->create([
            'username' => 'phase5_primary_only',
            'status' => 'active',
            'primary_branch_id' => $branch->id,
        ]);
        $user->roles()->attach($role->id);

        $customer = Customer::factory()->create([
            'branch_id' => $branch->id,
            'customer_number' => 'CUS-PHASE5-PRIMARY',
        ]);

        $this->assertSame([], $user->branches()->pluck('branches.id')->all());

        $groups = app(GlobalSearchService::class)->search($user, $customer->customer_number);
        $this->assertSame('CUS-PHASE5-PRIMARY', $groups[0]['results'][0]['identifier']);

        $this->actingAs($user)
            ->get(route('dashboard'))
            ->assertOk()
            ->assertSee('Phase 5 Primary Only');
    }

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

        $role = Role::create(['name' => 'phase5-dashboard-filter', 'display_name' => 'Phase 5 Dashboard Filter']);
        $role->permissions()->attach(Permission::where('name', 'reports.view')->firstOrFail()->id);

        $user = User::factory()->create([
            'username' => 'phase5_dashboard_filter',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $user->roles()->attach($role->id);
        $user->branches()->attach($branchA->id, ['is_primary' => true]);

        $this->actingAs($user)
            ->get(route('dashboard', ['branch_ids' => [$branchB->id]]))
            ->assertForbidden();
    }

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

        $role = Role::create(['name' => 'phase5-fixed-assets', 'display_name' => 'Phase 5 Fixed Assets']);
        $role->permissions()->attach(Permission::whereIn('name', ['fixed-assets.view', 'fixed-assets.reports.view', 'fixed-assets.reports.export'])->pluck('id'));

        $user = User::factory()->create([
            'username' => 'phase5_fixed_assets',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $user->roles()->attach($role->id);

        $assetA = $this->asset($business, $branchA, 'AST-P5-A', 'Primary Branch Asset');
        $assetB = $this->asset($business, $branchB, 'AST-P5-B', 'Other Branch Asset');

        $this->assertSame([], $user->branches()->pluck('branches.id')->all());

        $this->actingAs($user)
            ->get(route('fixed-assets.reports', [
                'report' => 'register',
                'from' => '2026-01-01',
                'to' => '2026-12-31',
            ]))
            ->assertOk()
            ->assertSee($assetA->asset_number)
            ->assertDontSee($assetB->asset_number);

        $csv = $this->actingAs($user)
            ->get(route('fixed-assets.reports.export', [
                'report' => 'register',
                'from' => '2026-01-01',
                'to' => '2026-12-31',
            ]))
            ->assertOk()
            ->streamedContent();

        $this->assertStringContainsString($assetA->asset_number, $csv);
        $this->assertStringNotContainsString($assetB->asset_number, $csv);

        $this->actingAs($user)
            ->get(route('fixed-assets.reports', [
                'report' => 'register',
                'from' => '2026-01-01',
                'to' => '2026-12-31',
                'branch_ids' => [$branchB->id],
            ]))
            ->assertForbidden();
    }

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

        $accountA = FinancialAccount::create([
            'branch_id' => $branchA->id,
            'name' => 'Phase 8 Primary Cash',
            'account_type' => 'cash',
            'opening_balance' => '100000.00',
            'current_balance' => '100000.00',
            'status' => 'active',
        ]);
        $accountB = FinancialAccount::create([
            'branch_id' => $branchB->id,
            'name' => 'Phase 8 Other Cash',
            'account_type' => 'cash',
            'opening_balance' => '100000.00',
            'current_balance' => '100000.00',
            'status' => 'active',
        ]);

        $accountant = User::factory()->create([
            'username' => 'phase8_primary_accountant',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $accountant->roles()->attach(Role::where('name', 'accountant')->firstOrFail()->id);

        $this->assertSame([], $accountant->branches()->pluck('branches.id')->all());

        $this->actingAs($accountant)
            ->get(route('expenses.create'))
            ->assertOk()
            ->assertSee($branchA->name)
            ->assertSee($accountA->name)
            ->assertDontSee($branchB->name)
            ->assertDontSee($accountB->name);

        $this->actingAs($accountant)
            ->get(route('account-transfers.create'))
            ->assertOk()
            ->assertSee($accountA->name)
            ->assertDontSee($accountB->name);

        $customer = Customer::factory()->create([
            'branch_id' => $branchA->id,
            'customer_number' => 'CUS-PHASE8-PRIMARY',
        ]);
        $product = LoanProduct::create([
            'business_id' => $business->id,
            'name' => 'Phase 8 Controller Product',
            'minimum_amount' => '10000.00',
            'maximum_amount' => '500000.00',
            'duration' => 2,
            'duration_unit' => 'months',
            'interest_rate' => '10.000000',
            'interest_calculation_method' => 'flat',
            'repayment_frequency' => 'monthly',
            'grace_period_days' => 0,
            'late_payment_penalty_type' => 'none',
            'late_payment_penalty_value' => '0.000000',
            'processing_fee_type' => 'fixed',
            'processing_fee_value' => '0.000000',
            'insurance_fee_type' => 'fixed',
            'insurance_fee_value' => '0.000000',
            'other_charges' => '0.00',
            'collateral_required' => false,
            'guarantor_required' => false,
            'status' => 'active',
        ]);
        $loan = Loan::create([
            'branch_id' => $branchA->id,
            'customer_id' => $customer->id,
            'loan_product_id' => $product->id,
            'sequence_number' => 1,
            'sequence_year' => (int) now()->format('Y'),
            'loan_number' => 'LN-PHASE8-PRIMARY',
            'principal' => '100000.00',
            'interest' => '10000.00',
            'processing_fee' => '0.00',
            'insurance_fee' => '0.00',
            'other_charges' => '0.00',
            'fees' => '0.00',
            'total_repayment' => '110000.00',
            'principal_outstanding' => '100000.00',
            'interest_outstanding' => '10000.00',
            'fees_outstanding' => '0.00',
            'penalties_outstanding' => '0.00',
            'total_outstanding' => '110000.00',
            'total_paid' => '0.00',
            'purpose' => 'Phase 8 controller scope regression',
            'schedule_start_date' => now()->format('Y-m-d'),
            'status' => 'active',
            'disbursed_at' => now(),
            'activated_at' => now(),
            'schedule_activated_at' => now(),
        ]);

        $cashier = User::factory()->create([
            'username' => 'phase8_primary_cashier',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $cashier->roles()->attach(Role::where('name', 'cashier')->firstOrFail()->id);

        $this->assertSame([], $cashier->branches()->pluck('branches.id')->all());

        $this->actingAs($cashier)
            ->get(route('loan-payments.index', ['search' => $loan->loan_number]))
            ->assertOk()
            ->assertSee($loan->loan_number)
            ->assertDontSee('No active loan matched this search.');
    }

    private function asset(Business $business, Branch $branch, string $number, string $name): FixedAsset
    {
        return FixedAsset::create([
            'business_id' => $business->id,
            'branch_id' => $branch->id,
            'asset_number' => $number,
            'name' => $name,
            'category' => 'Furniture',
            'acquisition_source' => 'opening',
            'acquisition_date' => '2026-08-01',
            'depreciation_start_date' => '2026-08-01',
            'acquisition_cost' => '1000.00',
            'residual_value' => '0.00',
            'depreciation_method' => 'straight_line',
            'useful_life_months' => 12,
            'accumulated_depreciation' => '0.00',
            'book_value' => '1000.00',
            'status' => 'active',
        ]);
    }
}
