<?php

use App\Enums\Permission as PermissionEnum;
use App\Models\Supplier;
use App\Models\User;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->seed(RolePermissionSeeder::class);
});

// ─── Helper ───────────────────────────────────────────────

function createSupplierUserWithPermission(PermissionEnum ...$permissions): User
{
    $user = User::factory()->create();

    $user->givePermissionTo(
        array_merge(
            [PermissionEnum::DASHBOARD_VIEW->value],
            array_map(fn (PermissionEnum $p) => $p->value, $permissions)
        )
    );

    $user->forgetCachedPermissions();

    return $user;
}

// ─── Index ────────────────────────────────────────────────

describe('Supplier Index', function () {
    test('authenticated user with permission can view supplier index', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW);

        Supplier::factory()->count(3)->create();

        $this->actingAs($user)
            ->get(route('admin.master.suppliers.index'))
            ->assertOk();
    });

    test('guest is redirected to login', function () {
        $this->get(route('admin.master.suppliers.index'))
            ->assertRedirect(route('login'));
    });

    test('user without permission is forbidden', function () {
        $user = User::factory()->create();

        $this->actingAs($user)
            ->get(route('admin.master.suppliers.index'))
            ->assertForbidden();
    });

    test('index returns suppliers with pagination', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW);

        Supplier::factory()->count(15)->create();

        $this->actingAs($user)
            ->get(route('admin.master.suppliers.index'))
            ->assertOk();
    });

    test('index can search suppliers by name', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW);

        Supplier::factory()->create(['name' => 'PT Maju Jaya']);
        Supplier::factory()->create(['name' => 'CV Berkah Tekstil']);

        $this->actingAs($user)
            ->get(route('admin.master.suppliers.index', ['search' => 'Maju']))
            ->assertOk();
    });
});

// ─── Store ────────────────────────────────────────────────

describe('Supplier Store', function () {
    test('authenticated user with permission can create a supplier', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_CREATE);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => 'PT Supplier Baru',
                'phone_number' => '081234567890',
                'address' => 'Jl. Merdeka No. 1',
            ])
            ->assertRedirect(route('admin.master.suppliers.index'));

        $this->assertDatabaseHas('suppliers', [
            'name' => 'PT Supplier Baru',
            'phone_number' => '081234567890',
            'address' => 'Jl. Merdeka No. 1',
        ]);
    });

    test('guest cannot create a supplier', function () {
        $this->post(route('admin.master.suppliers.store'), [
            'name' => 'PT Supplier Baru',
        ])->assertRedirect(route('login'));
    });

    test('user without create permission is forbidden', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => 'PT Supplier Baru',
            ])
            ->assertForbidden();

        $this->assertDatabaseCount('suppliers', 0);
    });

    test('name is required', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_CREATE);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => '',
            ])
            ->assertSessionHasErrors('name');

        $this->assertDatabaseCount('suppliers', 0);
    });

    test('name must not exceed 200 characters', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_CREATE);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => str_repeat('a', 201),
            ])
            ->assertSessionHasErrors('name');

        $this->assertDatabaseCount('suppliers', 0);
    });

    test('phone number must start with 08', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_CREATE);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => 'PT Supplier Baru',
                'phone_number' => '0211234567',
            ])
            ->assertSessionHasErrors('phone_number');

        $this->assertDatabaseCount('suppliers', 0);
    });

    test('phone number can be null', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_CREATE);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => 'PT Supplier Baru',
                'phone_number' => null,
            ])
            ->assertRedirect(route('admin.master.suppliers.index'));

        $this->assertDatabaseHas('suppliers', [
            'name' => 'PT Supplier Baru',
            'phone_number' => null,
        ]);
    });

    test('address can be null', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_CREATE);

        $this->actingAs($user)
            ->post(route('admin.master.suppliers.store'), [
                'name' => 'PT Supplier Baru',
                'address' => null,
            ])
            ->assertRedirect(route('admin.master.suppliers.index'));

        $this->assertDatabaseHas('suppliers', [
            'name' => 'PT Supplier Baru',
            'address' => null,
        ]);
    });
});

// ─── Update ───────────────────────────────────────────────

describe('Supplier Update', function () {
    test('authenticated user with permission can update a supplier', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_UPDATE);

        $supplier = Supplier::factory()->create(['name' => 'Nama Lama']);

        $this->actingAs($user)
            ->put(route('admin.master.suppliers.update', $supplier), [
                'name' => 'Nama Baru',
                'phone_number' => '089876543210',
                'address' => 'Jl. Baru No. 2',
            ])
            ->assertRedirect(route('admin.master.suppliers.index'));

        $this->assertDatabaseHas('suppliers', [
            'id' => $supplier->id,
            'name' => 'Nama Baru',
            'phone_number' => '089876543210',
            'address' => 'Jl. Baru No. 2',
        ]);
    });

    test('guest cannot update a supplier', function () {
        $supplier = Supplier::factory()->create();

        $this->put(route('admin.master.suppliers.update', $supplier), [
            'name' => 'Nama Baru',
        ])->assertRedirect(route('login'));
    });

    test('user without update permission is forbidden', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW);

        $supplier = Supplier::factory()->create(['name' => 'Nama Lama']);

        $this->actingAs($user)
            ->put(route('admin.master.suppliers.update', $supplier), [
                'name' => 'Nama Baru',
            ])
            ->assertForbidden();

        $this->assertDatabaseHas('suppliers', [
            'id' => $supplier->id,
            'name' => 'Nama Lama',
        ]);
    });

    test('name is required on update', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_UPDATE);

        $supplier = Supplier::factory()->create();

        $this->actingAs($user)
            ->put(route('admin.master.suppliers.update', $supplier), [
                'name' => '',
            ])
            ->assertSessionHasErrors('name');
    });

    test('name must not exceed 200 characters on update', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_UPDATE);

        $supplier = Supplier::factory()->create();

        $this->actingAs($user)
            ->put(route('admin.master.suppliers.update', $supplier), [
                'name' => str_repeat('a', 201),
            ])
            ->assertSessionHasErrors('name');
    });

    test('phone number validation on update', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_UPDATE);

        $supplier = Supplier::factory()->create();

        $this->actingAs($user)
            ->put(route('admin.master.suppliers.update', $supplier), [
                'name' => 'Nama Valid',
                'phone_number' => '123invalid',
            ])
            ->assertSessionHasErrors('phone_number');
    });
});

// ─── Destroy ──────────────────────────────────────────────

describe('Supplier Destroy', function () {
    test('authenticated user with permission can delete a supplier', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_DELETE);

        $supplier = Supplier::factory()->create();

        $this->actingAs($user)
            ->delete(route('admin.master.suppliers.destroy', $supplier))
            ->assertRedirect(route('admin.master.suppliers.index'));

        $this->assertSoftDeleted('suppliers', [
            'id' => $supplier->id,
        ]);
    });

    test('guest cannot delete a supplier', function () {
        $supplier = Supplier::factory()->create();

        $this->delete(route('admin.master.suppliers.destroy', $supplier))
            ->assertRedirect(route('login'));

        $this->assertNotSoftDeleted('suppliers', [
            'id' => $supplier->id,
        ]);
    });

    test('user without delete permission is forbidden', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW);

        $supplier = Supplier::factory()->create();

        $this->actingAs($user)
            ->delete(route('admin.master.suppliers.destroy', $supplier))
            ->assertForbidden();

        $this->assertNotSoftDeleted('suppliers', [
            'id' => $supplier->id,
        ]);
    });

    test('deleted supplier is soft deleted', function () {
        $user = createSupplierUserWithPermission(PermissionEnum::SUPPLIERS_VIEW, PermissionEnum::SUPPLIERS_DELETE);

        $supplier = Supplier::factory()->create();

        $this->actingAs($user)
            ->delete(route('admin.master.suppliers.destroy', $supplier));

        $this->assertSoftDeleted('suppliers', ['id' => $supplier->id]);
        $this->assertDatabaseHas('suppliers', ['id' => $supplier->id]);
    });
});

// ─── Supplier Model ───────────────────────────────────────

describe('Supplier Model', function () {
    test('supplier uses soft deletes', function () {
        $supplier = Supplier::factory()->create();

        $supplier->delete();

        expect($supplier->trashed())->toBeTrue();
    });

    test('supplier can have purchases', function () {
        $supplier = Supplier::factory()->create();

        expect($supplier->purchases)->toBeInstanceOf(Collection::class);
    });
});
