<?php

namespace Tests\Feature;

use App\Models\Branch;
use App\Models\Business;
use App\Models\Customer;
use App\Models\CustomerCreditScoreHistory;
use App\Services\BranchContext;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
use LogicException;
use Tests\TestCase;

class CreditScoreFoundationTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_credit_score_configuration_is_versioned_and_weights_total_one_hundred(): void
    {
        $this->assertSame('v1', config('credit_score.version'));
        $this->assertSame(100, array_sum(config('credit_score.weights')));
        $this->assertSame(300, config('credit_score.score.minimum'));
        $this->assertSame(850, config('credit_score.score.maximum'));
    }

    public function test_credit_score_foundation_schema_exists(): void
    {
        foreach ([
            'score_band',
            'score_version',
            'confidence',
            'thin_file',
            'manual_review_required',
            'last_trigger',
        ] as $column) {
            $this->assertTrue(Schema::hasColumn('customer_risk_profiles', $column), $column.' is missing from customer_risk_profiles.');
        }

        foreach ([
            'customer_id',
            'branch_id',
            'score',
            'score_band',
            'risk_level',
            'confidence',
            'thin_file',
            'manual_review_required',
            'score_version',
            'trigger',
            'component_scores',
            'factors',
            'explanation',
            'calculated_at',
            'created_by',
        ] as $column) {
            $this->assertTrue(Schema::hasColumn('customer_credit_score_histories', $column), $column.' is missing from customer_credit_score_histories.');
        }

        $this->assertTrue(Schema::hasColumn('loans', 'application_credit_score_history_id'));
    }

    public function test_credit_score_history_is_branch_scoped_and_customer_relationships_resolve(): void
    {
        [$branchA, $branchB, $customerA, $customerB] = $this->customerFixture();
        $context = app(BranchContext::class);

        $historyA = $this->history($customerA, $branchA, 724, 'good');
        $historyB = $this->history($customerB, $branchB, 615, 'fair');

        $this->assertSame([], CustomerCreditScoreHistory::query()->pluck('id')->all());

        $this->assertSame(
            [$historyA->id],
            $context->forBranch($branchA->id, fn () => CustomerCreditScoreHistory::query()->pluck('id')->all())
        );
        $this->assertSame(
            [$historyB->id],
            $context->forBranch($branchB->id, fn () => CustomerCreditScoreHistory::query()->pluck('id')->all())
        );

        $latestId = $context->forBranch(
            $branchA->id,
            fn () => Customer::query()->findOrFail($customerA->id)->latestCreditScoreHistory()->firstOrFail()->id
        );

        $this->assertSame($historyA->id, $latestId);
    }

    public function test_credit_score_history_model_rejects_mutation(): void
    {
        [$branchA, , $customerA] = $this->customerFixture();
        $history = $this->history($customerA, $branchA, 700, 'good');

        $this->expectException(LogicException::class);
        $history->update(['score' => 701]);
    }

    private function customerFixture(): array
    {
        $business = Business::firstOrFail();
        $branchA = Branch::create(['business_id' => $business->id, 'name' => 'Score A', 'status' => 'active']);
        $branchB = Branch::create(['business_id' => $business->id, 'name' => 'Score B', 'status' => 'active']);

        $customerA = Customer::create([
            'branch_id' => $branchA->id,
            'customer_number' => 'SCORE-A-001',
            'identity_mode' => 'without_nin',
            'first_name' => 'Alpha',
            'last_name' => 'Borrower',
            'phone' => '0712000001',
            'status' => 'active',
        ]);
        $customerB = Customer::create([
            'branch_id' => $branchB->id,
            'customer_number' => 'SCORE-B-001',
            'identity_mode' => 'without_nin',
            'first_name' => 'Beta',
            'last_name' => 'Borrower',
            'phone' => '0712000002',
            'status' => 'active',
        ]);

        return [$branchA, $branchB, $customerA, $customerB];
    }

    private function history(Customer $customer, Branch $branch, int $score, string $band): CustomerCreditScoreHistory
    {
        return CustomerCreditScoreHistory::create([
            'customer_id' => $customer->id,
            'branch_id' => $branch->id,
            'score' => $score,
            'score_band' => $band,
            'risk_level' => $band === 'fair' ? 'high' : 'moderate',
            'confidence' => 75,
            'thin_file' => false,
            'manual_review_required' => false,
            'score_version' => 'v1',
            'trigger' => 'test',
            'component_scores' => ['repayment_behaviour' => 80],
            'factors' => ['test_fixture' => true],
            'explanation' => 'Foundation test snapshot.',
            'calculated_at' => now(),
        ]);
    }
}
