<?php

namespace Tests\Feature;

use App\Models\Branch;
use App\Models\Business;
use App\Models\Customer;
use App\Models\Loan;
use App\Models\LoanProduct;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class BranchLoanProductAvailabilityTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_branch_allows_all_active_business_products_until_a_restriction_is_saved(): void
    {
        [$admin, $business, $branch, $customer, $productA, $productB] = $this->fixture();

        $this->assertTrue($branch->allowsLoanProduct($productA));
        $this->assertTrue($branch->allowsLoanProduct($productB));

        $futureProduct = $this->product($business, 'Future Product');
        $this->assertTrue($branch->allowsLoanProduct($futureProduct));

        $branch->loanProducts()->sync([$productA->id]);
        $branch->unsetRelation('loanProducts');

        $this->assertTrue($branch->allowsLoanProduct($productA));
        $this->assertFalse($branch->allowsLoanProduct($productB));
        $this->assertFalse($branch->allowsLoanProduct($futureProduct));

        $branch->loanProducts()->sync([]);
        $branch->unsetRelation('loanProducts');

        $this->assertTrue($branch->allowsLoanProduct($productA));
        $this->assertTrue($branch->allowsLoanProduct($productB));
        $this->assertTrue($branch->allowsLoanProduct($futureProduct));
    }

    public function test_branch_management_can_restrict_and_then_restore_all_products(): void
    {
        [$admin, $business, $branch, $customer, $productA, $productB] = $this->fixture();

        $this->actingAs($admin)->put(route('admin.branches.update', $branch), [
            'business_id' => $business->id,
            'name' => $branch->name,
            'status' => 'active',
            'loan_product_selection_present' => '1',
            'loan_product_ids' => [$productA->id],
        ])->assertRedirect(route('admin.branches.index'));

        $this->assertDatabaseHas('branch_loan_product', [
            'branch_id' => $branch->id,
            'loan_product_id' => $productA->id,
        ]);
        $this->assertDatabaseMissing('branch_loan_product', [
            'branch_id' => $branch->id,
            'loan_product_id' => $productB->id,
        ]);

        $this->actingAs($admin)->put(route('admin.branches.update', $branch), [
            'business_id' => $business->id,
            'name' => $branch->name,
            'status' => 'active',
            'loan_product_selection_present' => '1',
        ])->assertRedirect(route('admin.branches.index'));

        $this->assertDatabaseMissing('branch_loan_product', ['branch_id' => $branch->id]);
        $this->assertTrue($branch->fresh()->allowsLoanProduct($productA));
        $this->assertTrue($branch->fresh()->allowsLoanProduct($productB));
    }

    public function test_restricted_branch_rejects_a_non_selected_product_when_creating_a_loan(): void
    {
        [$admin, $business, $branch, $customer, $productA, $productB] = $this->fixture();
        $branch->loanProducts()->sync([$productA->id]);

        $this->actingAs($admin)->post(route('loans.store'), [
            'branch_id' => $branch->id,
            'customer_id' => $customer->id,
            'loan_product_id' => $productB->id,
            'principal' => '500000.00',
            'purpose' => 'Business stock',
            'schedule_start_date' => now()->format('Y-m-d'),
        ])->assertSessionHasErrors('loan_product_id');

        $this->assertSame(0, Loan::where('branch_id', $branch->id)->count());

        $this->actingAs($admin)->post(route('loans.store'), [
            'branch_id' => $branch->id,
            'customer_id' => $customer->id,
            'loan_product_id' => $productA->id,
            'principal' => '500000.00',
            'purpose' => 'Business stock',
            'schedule_start_date' => now()->format('Y-m-d'),
        ])->assertRedirect();

        $this->assertDatabaseHas('loans', [
            'branch_id' => $branch->id,
            'loan_product_id' => $productA->id,
        ]);
    }

    private function fixture(): array
    {
        $admin = User::where('email', 'admin@microfinance.local')->firstOrFail();
        $business = Business::firstOrFail();
        $branch = Branch::firstOrCreate(
            ['business_id' => $business->id, 'name' => 'Dodoma Product Rules'],
            ['status' => 'active'],
        );
        $customer = Customer::firstOrCreate(
            ['customer_number' => 'CUS-BR-PRODUCT-001'],
            [
                'branch_id' => $branch->id,
                'identity_mode' => 'without_nin',
                'first_name' => 'Neema',
                'last_name' => 'John',
                'phone' => '0755111222',
                'status' => 'active',
            ],
        );

        return [
            $admin,
            $business,
            $branch,
            $customer,
            $this->product($business, 'Branch Product A'),
            $this->product($business, 'Branch Product B'),
        ];
    }

    private function product(Business $business, string $name): LoanProduct
    {
        return LoanProduct::firstOrCreate(
            ['business_id' => $business->id, 'name' => $name],
            [
                'minimum_amount' => '100000.00',
                'maximum_amount' => '1000000.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' => 'fixed',
                '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',
            ],
        );
    }
}
