<?php

namespace Tests\Feature;

use App\Models\BlacklistRecord;
use App\Models\Branch;
use App\Models\Business;
use App\Models\Customer;
use App\Models\Role;
use App\Models\User;
use App\Services\BranchContext;
use App\Services\CustomerRiskService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

class CustomerManagementTest extends TestCase
{
    use RefreshDatabase;

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

    private function branch(string $code='DOM001'): Branch
    {
        return Branch::create(['business_id'=>Business::firstOrFail()->id,'name'=>$code.' Branch','code'=>$code,'status'=>'active']);
    }

    private function officer(Branch $branch, string $role='loan-officer'): User
    {
        $user=User::factory()->create(['employee_number'=>'EMP-'.fake()->unique()->numerify('####'),'username'=>fake()->unique()->userName(),'status'=>'active','primary_branch_id'=>$branch->id]);
        $user->roles()->attach(Role::where('name',$role)->firstOrFail());
        $user->branches()->attach($branch->id,['is_primary'=>true]);
        return $user;
    }

    public function test_authorized_officer_can_register_customer_with_permanent_number(): void
    {
        $branch=$this->branch(); $user=$this->officer($branch);
        $response=$this->actingAs($user)->post(route('customers.store'),[
            'branch_id'=>$branch->id,'identity_mode'=>'with_nin','first_name'=>'John','last_name'=>'Michael','nin'=>'19900101-12345-00001-00','phone'=>'0712345678','status'=>'active','region'=>'Dodoma','district'=>'Dodoma City','next_of_kin_name'=>'Jane Michael','next_of_kin_phone'=>'0755000000',
        ]);
        $customer=Customer::firstOrFail();
        $response->assertRedirect(route('customers.show',$customer));
        $this->assertMatchesRegularExpression('/^CUS-DOM001-\d{4}-000001$/',$customer->customer_number);
        $this->assertSame('255712345678',$customer->phone);
        $this->assertSame('Dodoma',$customer->address->region);
        $this->assertSame('Jane Michael',$customer->nextOfKin()->first()->full_name);
        $this->assertSame('255755000000',$customer->nextOfKin()->first()->phone);
        $this->assertSame('high',$customer->riskProfile->risk_level);
        $this->assertTrue($customer->riskProfile->manual_review_required);
        $this->assertDatabaseHas('audit_logs',['action'=>'customer.created','auditable_id'=>$customer->id]);
    }

    public function test_duplicate_phone_is_blocked_and_not_silently_created(): void
    {
        $branch=$this->branch(); $user=$this->officer($branch);
        Customer::factory()->create(['branch_id'=>$branch->id,'phone'=>'0711111111']);
        $this->actingAs($user)->post(route('customers.store'),['branch_id'=>$branch->id,'identity_mode'=>'without_nin','first_name'=>'Another','last_name'=>'Person','phone'=>'711111111','status'=>'active'])
            ->assertSessionHasErrors('duplicate');
        $this->assertSame(1,Customer::where('phone','255711111111')->count());
    }

    public function test_invalid_local_phone_number_is_rejected_before_customer_creation(): void
    {
        $branch=$this->branch('DOM007'); $user=$this->officer($branch);

        $this->actingAs($user)->post(route('customers.store'),[
            'branch_id'=>$branch->id,'identity_mode'=>'without_nin','first_name'=>'Invalid','last_name'=>'Phone','phone'=>'7123456789','status'=>'active',
        ])->assertSessionHasErrors('phone');

        $this->assertDatabaseMissing('customers',['first_name'=>'Invalid','last_name'=>'Phone']);
    }

    public function test_branch_user_cannot_open_customer_from_another_branch(): void
    {
        $a=$this->branch('DOM002'); $b=$this->branch('ARU002'); $user=$this->officer($a);
        $customer=Customer::factory()->create(['branch_id'=>$b->id]);
        $this->actingAs($user)->get(route('customers.show',$customer))->assertForbidden();
    }

    public function test_nin_lookup_gracefully_supports_manual_fallback_when_provider_is_not_configured(): void
    {
        $branch=$this->branch('DOM003'); $user=$this->officer($branch);
        $this->actingAs($user)->postJson(route('customers.nin-lookup'),['nin'=>'12345678901234567890'])
            ->assertOk()->assertJson(['configured'=>false,'found'=>false]);
    }

    public function test_customer_documents_are_stored_privately_and_can_be_downloaded_by_authorized_user(): void
    {
        Storage::fake('local');
        $branch=$this->branch('DOM004'); $user=$this->officer($branch); $customer=Customer::factory()->create(['branch_id'=>$branch->id]);
        $this->actingAs($user)->post(route('customers.documents.store',$customer),['document_type'=>'National ID','document'=>UploadedFile::fake()->create('id.pdf',100,'application/pdf')])->assertRedirect();
        $document=$customer->documents()->firstOrFail();
        Storage::disk('local')->assertExists($document->file_path);
        $this->actingAs($user)->get(route('customers.documents.download',[$customer,$document]))->assertOk();
    }

    public function test_blacklist_updates_explainable_risk_and_resolution_removes_active_blacklist_factor(): void
    {
        $branch=$this->branch('DOM005'); $user=$this->officer($branch); $customer=Customer::factory()->create(['branch_id'=>$branch->id]);
        app(BranchContext::class)->forBranch($branch->id, fn () => app(CustomerRiskService::class)->refresh($customer));
        $this->actingAs($user)->post(route('customers.watchlist.store',$customer),['type'=>'blacklist','reason'=>'False documents'])->assertRedirect();
        $customer->refresh();
        $profile=$customer->riskProfile->fresh();
        $this->assertTrue($profile->manual_review_required);
        $this->assertContains('active_blacklist',collect($profile->factors['overlays'] ?? [])->pluck('key')->all());
        $record=BlacklistRecord::firstOrFail();
        $this->actingAs($user)->post(route('customers.watchlist.resolve',[$customer,$record]),['resolution_notes'=>'Cleared by management'])->assertRedirect();
        $profile=$customer->riskProfile->fresh();
        $this->assertNotContains('active_blacklist',collect($profile->factors['overlays'] ?? [])->pluck('key')->all());
    }

    public function test_customer_profile_tabs_render(): void
    {
        $branch=$this->branch('DOM006'); $user=$this->officer($branch); $customer=Customer::factory()->create(['branch_id'=>$branch->id]);
        app(BranchContext::class)->forBranch($branch->id, fn () => app(CustomerRiskService::class)->refresh($customer));
        foreach(['overview','personal','kyc','documents','guarantors','blacklist','activity'] as $tab) {
            $this->actingAs($user)->get(route('customers.show',[$customer,'tab'=>$tab]))->assertOk();
        }
    }
}
