<?php

namespace Tests\Feature;

use App\Models\Branch;
use App\Models\Business;
use App\Models\Collateral;
use App\Models\CollateralCategory;
use App\Models\CollateralFile;
use App\Models\Customer;
use App\Models\Role;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

class CollateralManagementTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_super_admin_can_register_collateral_with_system_code_and_initial_history(): void
    {
        Storage::fake('local');
        [$admin, $branch, $customer, $category] = $this->fixture();

        $this->actingAs($admin)->get(route('collateral.create'))
            ->assertOk()
            ->assertSee('Register Collateral');

        $response = $this->actingAs($admin)->post(route('collateral.store'), [
            'customer_id' => $customer->id,
            'branch_id' => $branch->id,
            'category_id' => $category->id,
            'item' => '55-inch Smart TV',
            'brand' => 'Samsung',
            'serial_number' => 'SN-001',
            'estimated_value' => '900000.00',
            'accepted_value' => '750000.00',
            'condition' => 'Good',
            'received_at' => now()->format('Y-m-d'),
            'store_room' => 'Store Room A',
            'shelf' => 'Shelf 2',
            'status' => 'pending_inspection',
            'photos' => [
                UploadedFile::fake()->image('tv-front.jpg'),
                UploadedFile::fake()->image('tv-back.jpg'),
                UploadedFile::fake()->image('tv-serial.jpg'),
            ],
        ]);

        $collateral = Collateral::where('customer_id', $customer->id)->firstOrFail();
        $response->assertRedirect(route('collateral.show', $collateral));
        $this->assertMatchesRegularExpression('/^COL-[A-Z0-9]+-000001$/', $collateral->code);
        $this->assertDatabaseHas('collateral_movements', [
            'collateral_id' => $collateral->id,
            'action' => 'received',
            'to_status' => 'pending_inspection',
        ]);
        $this->assertSame(3, CollateralFile::withoutGlobalScopes()->where('collateral_id', $collateral->id)->where('kind', 'photo')->count());
        $this->assertDatabaseHas('audit_logs', ['action' => 'collateral.created', 'auditable_id' => $collateral->id]);

        $this->actingAs($admin)->get(route('collateral.show', $collateral))
            ->assertOk()
            ->assertSee($collateral->code)
            ->assertSee('Custody history')
            ->assertSee('Select several collateral images and upload them together.');
    }

    public function test_authorized_user_can_upload_multiple_photos_to_existing_collateral(): void
    {
        Storage::fake('local');
        [$admin, $branch, $customer, $category] = $this->fixture();
        $collateral = $this->createCollateral($branch, $customer, $category, 'COL-MULTI-000001');

        $response = $this->actingAs($admin)->post(route('collateral.files.store', $collateral), [
            'kind' => 'photo',
            'attachments' => [
                UploadedFile::fake()->image('front.jpg'),
                UploadedFile::fake()->image('left.jpg'),
                UploadedFile::fake()->image('right.jpg'),
                UploadedFile::fake()->image('serial-number.jpg'),
            ],
            'notes' => 'Full collateral image set.',
        ]);

        $response
            ->assertRedirect()
            ->assertSessionHas('success', '4 collateral photos uploaded successfully.');

        $photos = CollateralFile::withoutGlobalScopes()
            ->where('collateral_id', $collateral->id)
            ->where('kind', 'photo')
            ->orderBy('id')
            ->get();

        $this->assertCount(4, $photos);
        $this->assertSame(
            ['front.jpg', 'left.jpg', 'right.jpg', 'serial-number.jpg'],
            $photos->pluck('original_name')->all(),
        );
        $this->assertTrue($photos->every(fn (CollateralFile $photo) => $photo->notes === 'Full collateral image set.'));
        $this->assertSame(
            4,
            \DB::table('audit_logs')
                ->where('action', 'collateral.file_uploaded')
                ->whereIn('auditable_id', $photos->pluck('id'))
                ->count(),
        );
    }

    public function test_collateral_custody_changes_preserve_permanent_history(): void
    {
        [$admin, $branch, $customer, $category] = $this->fixture();
        $collateral = $this->createCollateral($branch, $customer, $category, 'COL-TEST01-000001');

        $this->actingAs($admin)->post(route('collateral.move', $collateral), [
            'status' => 'accepted',
            'store_room' => 'Vault',
            'shelf' => 'A1',
            'notes' => 'Inspection completed.',
        ])->assertRedirect();

        $this->actingAs($admin)->post(route('collateral.move', $collateral), [
            'status' => 'in_custody',
            'store_room' => 'Vault',
            'shelf' => 'B3',
            'notes' => 'Moved to long-term custody shelf.',
        ])->assertRedirect();

        $this->assertSame(2, $collateral->movements()->count());
        $this->assertDatabaseHas('collateral_movements', ['collateral_id' => $collateral->id, 'from_status' => 'pending_inspection', 'to_status' => 'accepted']);
        $this->assertDatabaseHas('collateral_movements', ['collateral_id' => $collateral->id, 'from_status' => 'accepted', 'to_status' => 'in_custody', 'to_shelf' => 'B3']);
        $this->assertSame('in_custody', $collateral->fresh()->status);
        $this->assertSame('B3', $collateral->fresh()->shelf);
    }

    public function test_branch_user_cannot_view_collateral_from_another_branch(): void
    {
        $business = Business::firstOrFail();
        $branchA = Branch::create(['business_id' => $business->id, 'name' => 'Dodoma', 'status' => 'active']);
        $branchB = Branch::create(['business_id' => $business->id, 'name' => 'Arusha', 'status' => 'active']);
        $category = CollateralCategory::where('business_id', $business->id)->firstOrFail();
        $customerB = $this->customer($branchB, 'CUS-ARU-001', '0755000002');
        $collateral = $this->createCollateral($branchB, $customerB, $category, 'COL-ARU-000001');

        $user = User::factory()->create([
            'name' => 'Dodoma Branch Admin',
            'username' => 'dodoma_admin',
            'status' => 'active',
            'primary_branch_id' => $branchA->id,
        ]);
        $user->roles()->attach(Role::where('name', 'branch-administrator')->firstOrFail());
        $user->branches()->attach($branchA->id, ['is_primary' => true]);

        $this->actingAs($user)->get(route('collateral.show', $collateral))->assertForbidden();
        $this->actingAs($user)->get(route('collateral.index'))->assertDontSee($collateral->code);
    }

    public function test_collateral_can_be_found_by_generated_code_and_printed(): void
    {
        [$admin, $branch, $customer, $category] = $this->fixture();
        $collateral = $this->createCollateral($branch, $customer, $category, 'COL-SEARCH-000001');

        $this->actingAs($admin)->get(route('collateral.index', ['search' => 'COL-SEARCH-000001']))
            ->assertOk()
            ->assertSee('COL-SEARCH-000001');

        $this->actingAs($admin)->get(route('collateral.label', $collateral))
            ->assertOk()
            ->assertSee('COL-SEARCH-000001')
            ->assertSee('<svg', false);

        $this->actingAs($admin)->get(route('collateral.receipt', $collateral))
            ->assertOk()
            ->assertSee('Collateral Receipt')
            ->assertSee($customer->full_name);
    }

    public function test_collateral_categories_are_configurable(): void
    {
        $admin = User::where('email', 'admin@microfinance.local')->firstOrFail();
        $business = Business::firstOrFail();

        $this->actingAs($admin)->get(route('collateral.categories.index'))
            ->assertOk()
            ->assertSee('Collateral Categories')
            ->assertSee('Television');

        $this->actingAs($admin)->post(route('collateral.categories.store'), [
            'business_id' => $business->id,
            'name' => 'Agricultural Equipment',
            'description' => 'Farm equipment accepted as security.',
            'status' => 'active',
        ])->assertRedirect();

        $this->assertDatabaseHas('collateral_categories', [
            'business_id' => $business->id,
            'name' => 'Agricultural Equipment',
            'status' => 'active',
        ]);
    }

    private function fixture(): array
    {
        $admin = User::where('email', 'admin@microfinance.local')->firstOrFail();
        $business = Business::firstOrFail();
        $branch = Branch::create(['business_id' => $business->id, 'name' => 'Mwanza', 'status' => 'active']);
        $customer = $this->customer($branch, 'CUS-MZA-001', '0755000001');
        $category = CollateralCategory::where('business_id', $business->id)->where('name', 'Television')->firstOrFail();

        return [$admin, $branch, $customer, $category];
    }

    private function customer(Branch $branch, string $number, string $phone): Customer
    {
        return Customer::create([
            'branch_id' => $branch->id,
            'customer_number' => $number,
            'identity_mode' => 'without_nin',
            'first_name' => 'Amina',
            'last_name' => 'Juma',
            'phone' => $phone,
            'status' => 'active',
        ]);
    }

    private function createCollateral(Branch $branch, Customer $customer, CollateralCategory $category, string $code): Collateral
    {
        return Collateral::create([
            'customer_id' => $customer->id,
            'branch_id' => $branch->id,
            'category_id' => $category->id,
            'sequence_number' => 1,
            'code' => $code,
            'item' => 'Test item',
            'accepted_value' => '500000.00',
            'received_at' => now(),
            'status' => 'pending_inspection',
        ]);
    }
}
